<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Guenter</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Guenter"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/Guenter"/>
	<updated>2026-04-09T22:30:06Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=69285</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=69285"/>
		<updated>2012-11-23T12:04:27Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Datentypen: wire, reg */ Initialer Wert für reg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.&amp;amp;nbsp;B. prozedurale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Probleme in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.&amp;amp;nbsp;B. C++, nimmt man Objekte und unterteilt ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch die gesamte Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design Taktgenau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthetisierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthetisierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.&amp;amp;nbsp;B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthetisierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthetisierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthetisierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthetisierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Wie bei einer Programmiersprache üblich, müssen Datentypen vor ihrer Benutzung deklariert werden. Das geschieht unter Verilog wie folgt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
wire a;&lt;br /&gt;
reg b;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Einem reg wird in diesem Fall der Wert x zugewiesen und einem wire der Wert z. Bei der Deklaration kann einem reg auch bereits ein Anfangswert zugewiesen werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
reg b = 0;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;   // ??? Widerspruch zu &amp;quot;Ein reg muss innerhalb eines always oder initial Blocks seine Werte zugewiesen bekommen&amp;quot;&lt;br /&gt;
                       // Das ist richtig, aber der Einfachheit halber wurde das weggelassen.&lt;br /&gt;
                       // Es wäre auch möglich, eine &amp;quot;assign&amp;quot;-Anweisung zu verwenden&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll nun in diesem Beispiel die Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann es wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthetisierbarer Logik findet es weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthetisierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten verzögert und dann mit der Ausführung des ihm folgenden Konstruktes weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Zuweisung clk = ~clk; im Simulator vom momentanen Zeitpunkt um 10 Zeiteinheiten verzögert ausgeführt wird. Bei der Zuweisung selber wird dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthetisierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernt. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedes Mal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung erneut ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthetisierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen, dass diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039;-Blöcke, die parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039;-Block basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039;-Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039;-Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eines der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039;-Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht, wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signale benutzt, d.h. Signale die ein Bit breit sind. Ein Bus wird von dem &#039;&#039;wire&#039;&#039;-Statement abgeleitet. Er wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;          // Setze nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setze Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setze Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setze Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite festgelegt und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; beschrieben. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweiften Klammern beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speichermodellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Aus der Programmiersprache C ist das Konzept der Felder bekannt, um Elemente gleichen Datentyps aufzuzählen. In Verilog wird das gleiche Konstrukt z.&amp;amp;nbsp;B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8-Bit-breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Syntax ist nur eine Verschmelzung der Syntaxen von Vektordefinitionen (die Bitbreite steht vor dem Bezeichner) mit der der Definition von Feldern (die Anzahl der Elemente steht nach dem Bezeichner).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die erste Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht, von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen, ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist es auch möglich, mehrdimensionale Speicher zu definieren, wie z.&amp;amp;nbsp;B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle möchte ich auf einen Kommentar von Jan Decaluwe, dem Entwickler von [http://www.myhdl.org MyHDL] hinweisen, der die Regelung als nicht notwendig erachtet und für die Mischung der beiden Zuweisungsarten eintritt:&lt;br /&gt;
&lt;br /&gt;
http://article.gmane.org/gmane.comp.python.myhdl/827&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.&amp;amp;nbsp;B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz, dass Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.&amp;amp;nbsp;B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 14&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 16-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanden, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 14&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichsoperationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn ergeben größer- und kleiner-Operationen immer FALSCH wenn ein x- oder z-Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durchzuführen, gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus:&lt;br /&gt;
Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthetisierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.&amp;amp;nbsp;B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.&amp;amp;nbsp;B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.&amp;amp;nbsp;B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.&amp;amp;nbsp;B. [http://gtkwave.sourceforge.net/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.&amp;amp;nbsp;B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.&amp;amp;nbsp;B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthetisierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden Flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
*[http://doolittle.icarus.com/~larry/vhd2vl/ VHDL to Verilog Konverter] unter Linux, Programme FLEX und Gnu-Bison müssen installiert sein&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=39265</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=39265"/>
		<updated>2009-09-24T09:49:26Z</updated>

		<summary type="html">&lt;p&gt;Guenter: Rechschreibfehler behoben; große synthesierbar -&amp;gt; synthetisierbar Umwandlung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteilt ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design Taktgenau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthetisierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthetisierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthetisierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthetisierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthetisierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthetisierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthetisierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthetisierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten verzögert und dann mit der Ausführung des ihm folgenden Konstruktes weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Zuweisung clk = ~clk; im Simulator vom momentanen Zeitpunkt um 10 Zeiteinheiten verzögert ausgeführt wird. Bei der Zuweisung selber wird dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthetisierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernt. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung erneut ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthetisierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signale benutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;          // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite festgelegt und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; beschrieben. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweiften Klammern beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle möchte ich auf einen Kommentar von Jan Decaluwe, dem Entwickler von [http://www.myhdl.org MyHDL] hinweisen, der die Regelung als nicht notwendig erachtet und für die Mischung der beiden Zuweisungsarten eintritt:&lt;br /&gt;
&lt;br /&gt;
http://article.gmane.org/gmane.comp.python.myhdl/827&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanden, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthetisierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthetisierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
*[http://doolittle.icarus.com/~larry/vhd2vl/ VHDL to Verilog Konverter] unter Linux, Programme FLEX und Gnu-Bison müssen installiert sein&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34749</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34749"/>
		<updated>2009-03-03T19:34:05Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung */  Hinweis über die möglische Mischung mit Link zu  Jan Decaluwes Nachricht&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteilt ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten verzögert und dann mit der Ausführung des ihm folgenden Konstruktes weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Zuweisung clk = ~clk; im Simulator vom momentanen Zeitpunkt um 10 Zeiteinheiten verzögert ausgeführt wird. Bei der Zuweisung selber wird dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung erneut ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signale benutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;          // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite festgelegt und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; beschrieben. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweiften Klammern beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle möchte ich auf einen Kommentar von Jan Decaluwe, dem Entwickler von [http://www.myhdl.org MyHDL] hinweisen, der die Regelung als nicht notwendig erachtet und für die Mischung der beiden Zuweisungsarten eintritt:&lt;br /&gt;
&lt;br /&gt;
http://article.gmane.org/gmane.comp.python.myhdl/827&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34747</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34747"/>
		<updated>2009-03-03T19:15:23Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung */  Schreibfehler&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteilt ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten verzögert und dann mit der Ausführung des ihm folgenden Konstruktes weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Zuweisung clk = ~clk; im Simulator vom momentanen Zeitpunkt um 10 Zeiteinheiten verzögert ausgeführt wird. Bei der Zuweisung selber wird dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung erneut ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signale benutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;          // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite festgelegt und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; beschrieben. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweiften Klammern beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34746</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34746"/>
		<updated>2009-03-03T19:09:58Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* always, initial */  Tippfehler&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteilt ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten verzögert und dann mit der Ausführung des ihm folgenden Konstruktes weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Zuweisung clk = ~clk; im Simulator vom momentanen Zeitpunkt um 10 Zeiteinheiten verzögert ausgeführt wird. Bei der Zuweisung selber wird dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung erneut ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34149</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=34149"/>
		<updated>2009-02-03T19:09:56Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Entwicklung der Hardwarebeschreibungssprache */  Schreibfehler behoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteilt ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten verzögert und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Zuweisung clk = ~clk; im Simulator vom momentanen Zeitpunkt um 10 Zeiteinheiten verzögert ausgeführt wird. Bei der Zuweisung selber wird dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=33796</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=33796"/>
		<updated>2009-01-13T19:46:21Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* always, initial */  Zutreffendere Formulierung des Verzögerungszeichens&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten verzögert und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Zuweisung clk = ~clk; im Simulator vom momentanen Zeitpunkt um 10 Zeiteinheiten verzögert ausgeführt wird. Bei der Zuweisung selber wird dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31863</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31863"/>
		<updated>2008-10-16T13:52:47Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Verilog für Simulation */ Einheitliche Schreibweise von compilieren&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, dass letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer kompilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden. Der Simulator arbeitet den übersetzten Quellcode in Zeitschritten ab. Dadurch kann die parallele Funktion von Hardware simuliert werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31707</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31707"/>
		<updated>2008-10-06T15:16:22Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Logische Operationen */ Schreibfehler behoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen verknüpft werden. Wie von den gängigen Programmiersprachen bekannt, unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&amp;amp;&amp;amp;&#039;&#039;&#039;  --&amp;gt; AND&lt;br /&gt;
* &#039;&#039;&#039;||&#039;&#039;&#039;  --&amp;gt; OR&lt;br /&gt;
* &#039;&#039;&#039;!&#039;&#039;&#039;   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31706</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31706"/>
		<updated>2008-10-06T15:12:14Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Arithmetische Operationen, signed, $signed */  Kleine Erweiterung der Erklärung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operationen gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen. Der $signed() System Task wandelt einen unsigned Datentypen in einen signed um.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31705</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=31705"/>
		<updated>2008-10-06T15:07:02Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Logische Bit-Operationen */ Zur besseren Lesbarkeit die Operatoren Fett geschrieben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;|&#039;&#039;&#039;     --&amp;gt; OR&lt;br /&gt;
*&#039;&#039;&#039;&amp;amp;&#039;&#039;&#039;     --&amp;gt; AND&lt;br /&gt;
*&#039;&#039;&#039;~&#039;&#039;&#039;     --&amp;gt; NOT&lt;br /&gt;
*&#039;&#039;&#039;^&#039;&#039;&#039;     --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*&#039;&#039;&#039;~&amp;amp;&#039;&#039;&#039;    --&amp;gt; NAND&lt;br /&gt;
*&#039;&#039;&#039;~|&#039;&#039;&#039;    --&amp;gt; NOR&lt;br /&gt;
*&#039;&#039;&#039;^~&#039;&#039;&#039; oder &#039;&#039;&#039;~^&#039;&#039;&#039;      --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=JTAG&amp;diff=31110</id>
		<title>JTAG</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=JTAG&amp;diff=31110"/>
		<updated>2008-09-16T12:45:40Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* FPGA JTAG */ FCPU-X platform cable&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;J&#039;&#039;&#039;oint &#039;&#039;&#039;T&#039;&#039;&#039;est &#039;&#039;&#039;A&#039;&#039;&#039;ction &#039;&#039;&#039;G&#039;&#039;&#039;roup, entwickelte den Standard IEEE 1149.1. Das JTAG-Protokoll ermöglicht das Programmieren, Debuggen und Testen von ICs, [[Prozessor]]en und [[FPGA]]s direkt in der Schaltung. Näheres insbesondere zu den möglichen Steckerbelegungen siehe in der [http://hri.sourceforge.net/tools/jtag_faq_org.html JTAG FAQ].&lt;br /&gt;
&lt;br /&gt;
= Hardware =&lt;br /&gt;
&lt;br /&gt;
== AVR JTAG ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.atmel.com/dyn/products/tools_card.asp?tool_id=2737 AVR JTAGICE] (neuerdings gelegentlich auch &#039;&#039;JTAGICE mkI&#039;&#039; genannt) von Atmel.&lt;br /&gt;
* [http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3353 AVR JTAGICE mkII] von Atmel.&lt;br /&gt;
* [http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3891 AVR Dragon] von Atmel.&lt;br /&gt;
** [http://www.atmel.com/dyn/resources/prod_documents/doc8112.pdf AVR077: Opto Isolated Emulation for the DebugWIRE] (auch für AVR JTAGICE mkII nützlich)&lt;br /&gt;
* [http://gandalf.arubi.uni-kl.de/avr_projects/evertool/index.html Evertool und Evertool light] von Martin Thomas. Evertool unterstützt JTAG analog zu AVR JTAGICE und [[ISP]] nach [[STK500]] Protokoll. Evertool light nur JTAG. &lt;br /&gt;
* [http://aquaticus.info/jtag JTAG for AVR processors] bei Aquaticus ROV. (Englisch)&lt;br /&gt;
* [http://www.olimex.com/dev/avr-jtag.html AVR-JTAG] und [http://www.olimex.com/dev/avr-usb-jtag.html AVR-USB-JTAG] von [http://www.olimex.com/dev/index.html Olimex] (kommerziell). Alternativer Lieferant ist der [http://elmicro.com/de/avrjtag.html Elektronikladen].&lt;br /&gt;
* [http://www.gadgetpool.de/bestellen/catalog/product_info.php/cPath/22_27/products_id/35 AVR-JTAG] und [http://www.gadgetpool.de/bestellen/catalog/product_info.php/cPath/22_27/products_id/52 AVR-USB-JTAG] von [http://www.gadgetPool.de gadgetPool] (kommerziell)&lt;br /&gt;
* [http://www.floppyspongeonline.com/automation/isojtagisp/isojtagisp.php IsoJtagISP] und [http://www.floppyspongeonline.com/automation/isojtag/isojtag.php IsoJTAG] von Floppy Sponge Automation ([[USB]], optisch isoliert)&lt;br /&gt;
* [http://www.ere.co.th/(gs5afz55q5idyyn0a1ibkl45)/default.aspx?RedirectPage=Products&amp;amp;RedirectPage1=ProductsDetail&amp;amp;ProductID=56 JTAGAVRU1] (AVR JTAGICE kompatibel, USB, 1.8-5.5V)&lt;br /&gt;
* [http://www.avrfreaks.net/index.php?module=Freaks%20Tools&amp;amp;func=viewItem&amp;amp;item_id=630 JTAGcable II] (AVR JTAGICE kompatibel, USB, 1.8-6 V)&lt;br /&gt;
* [http://www.miklobit.com/JTAG_TWICE.530+B6Jkw9Mw__.0.html MB-JTAG-TWICE] (AVR JTAGICE kompatibel, RS232, 2.7-5.5V, +ISP STK500v2) - Free update to version compatible with AVR JTAG MKII (coming soon)&lt;br /&gt;
&lt;br /&gt;
== ARM JTAG ==&lt;br /&gt;
&lt;br /&gt;
=== USB Anschluss auf Basis des FTDI FT2232 ===&lt;br /&gt;
* [http://www.fh-augsburg.de/~hhoegl/proj/usbjtag/usbjtag.html USB to JTAG Interface] von Hubert Högl, Schaltplan&lt;br /&gt;
* [http://www.embedded-projects.net/index.php?page_id=175 USB JTAG Interface für usbprog und OpenOCD] von Benedikt Sauter (Zurzeit gibt es Bausätze für 22 EUR. Der Adapter ist ein Universaladapter der mit verschiedenen Firmwares zu verschiedenen Geräte werden kann. Pläne, Quelltexte usw... Open Source!!!)&lt;br /&gt;
* [http://www.amontec.com/index.shtml Amontec] JTAGkey, JTAGkey-Tiny&lt;br /&gt;
* [http://www.luminarymicro.com/products/ekk-lm3s811_evaluation_kit.html EKK-LM3S811] von LMI. Auf dem Testboard ist ein &amp;quot;on-board&amp;quot; JTAG-Adapter, der zu Ansteuerung des LM3S811 auf dem Board genutzt wird, aber auch an externe Controller angeschlossen werden kann. (Alle LMI Testboards verfügen über den JTAG Ein- und Ausgang.)&lt;br /&gt;
* [http://www.olimex.com/dev/arm-usb-ocd.html ARM-USB-OCD] von Olimex&lt;br /&gt;
* [http://www.signalyzer.com/ Signalyzer Tool]&lt;br /&gt;
&lt;br /&gt;
=== Parallelport-Anschluss (Wiggler und Wiggler-&amp;quot;kompatibel&amp;quot;) ===&lt;br /&gt;
* [http://www.macraigor.com/hwproducts.htm Macraigor] Original Wiggler&lt;br /&gt;
* [http://www.olimex.com/dev/arm-jtag.html Olimex ARM-JTAG] Wiggler-Nachbau&lt;br /&gt;
* [http://www.k9spud.com/jtag/ k9spud Wiggler-Schaltplan]&lt;br /&gt;
* [http://bbs.circuitcellar.com/phpBB2/viewtopic.php?p=10059&amp;amp; bigakis Wiggler-Schaltplan] (74HC244 Levelshifter, BC547 Transistor zum Invertieren)&lt;br /&gt;
* [http://wiki.openwrt.org/OpenWrtDocs/Customizing/Hardware/JTAG_Cable Wiggler Schaltplan] von OpenWRT (ebenfalls mit 74HC244).&lt;br /&gt;
* [http://www.st.com/stonline/products/literature/um/12322.pdf ST FlashLink JTAG Programming Cable] STM Application-Note&lt;br /&gt;
&lt;br /&gt;
Man findet einige Schaltpläne für Wiggler-Nachbauten im Netz. Nicht alle sind identisch. Der original Schaltplan von Macraigor ist meines (M. Thomas) Wissens nicht verfügbar. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;Vollständige&amp;quot; Belegung des Wiggler-Clones von Olimex (Quelle: sparkfun-Forum)&lt;br /&gt;
* DB25.2 -&amp;gt; INVERSE -&amp;gt; JTAG.15 (NTRST) (mthomas: hier ist wohl nSRST gemeint)&lt;br /&gt;
* DB25.3 -&amp;gt; JTAG.7 (TMS)&lt;br /&gt;
* DB25.4 -&amp;gt; JTAG.9 (TCK)&lt;br /&gt;
* DB25.5 -&amp;gt; JTAG.5 (TDI)&lt;br /&gt;
* DB25.6 -&amp;gt; JTAG.3 (TRST)&lt;br /&gt;
* DB25.9 -&amp;gt; VCC for the Level shifter i.e. JTAG enable/disable&lt;br /&gt;
* DB25.11 &amp;lt;- JTAG.13 (TDO)&lt;br /&gt;
* DB25.13 &amp;lt;- Target VCC sense (only when JTAG is enabled i.e. DB26.9 = 1) &lt;br /&gt;
&lt;br /&gt;
DB25.18, DB25.19, DB25.20, DB25.21, DB25.22, DB25.23, DB25.24, DB25.25 werden mit GND verbunden.&lt;br /&gt;
&lt;br /&gt;
Soll das Wiggler-Interface auch mit der Software ocdremote von Macraigor genutzt werden, ist eine Brücke zwischen zwischen DB25.8 und DB25.15 einzubauen. ocdremote ab (ca.) Version 2.06 erkennt daran das original Wiggler und auch einen mit der Brücke ausgestattenen Nachbau. Nutzt man zur Ansteuerung andere Software (z.B. OpenOCD oder H-JTAG) wird diese Verbindung nicht benötigt.&lt;br /&gt;
&lt;br /&gt;
Man beachte die Beschaltung von SRST und TRST: &lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird Pin DB25.2 des Druckeranschlusses über eine Inverterschaltung (NPN Transistor) mit dem Reset-Pin des ARM-Controllers verbunden (&#039;&#039;&#039;nSRST&#039;&#039;&#039;). &lt;br /&gt;
&lt;br /&gt;
Pin DB25.6 des Druckeranschlusses wird über Levelshifter direkt mit dem &#039;&#039;&#039;TRST&#039;&#039;&#039;-Pin des Controllers verbunden. In manchen Schaltplänen findet man auch für TRST einen Inverter, aber dies scheint eher unüblich. &lt;br /&gt;
&lt;br /&gt;
Bei den sonstigen Pinbelegungen herrscht weitestgehend Einigkeit. Man muss lediglich Levelshifter ([[Pegelwandler]]) zwischenschalten, um zwischen den 5V des Druckeranschlusses und der Spannung des Controllers (üblicherweise 3,3V) zu &amp;quot;übersetzen&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Allein ein 74HC244 als Levelshifter, wie in vielen Schaltungen verwendet, ist nicht ideal. Der Baustein wird dabei mit 3,3V aus der Zielschaltung betrieben und die Anpassung an die nominell 5V vom Druckerport an die 3,3V des HC244 erfolgt entweder durch Spannungsteiler oder durch Strombegrenzungswiderstände und die internen Überspannungsschutzdioden. Das Ausgangssignal TDO zurück zum Druckeranschluss ist maximal 3,3V. Beides nicht optimal aber es funktioniert zumindest meistens. Aufwändigere Schaltungen, wie z.B. der Olimex Wiggler-Nachbau (&amp;quot;ARM-JTAG&amp;quot;), nutzen eine Kombination aus einem 74AC244 und einem 74LCX244.&lt;br /&gt;
&lt;br /&gt;
=== sonstige ===&lt;br /&gt;
&lt;br /&gt;
* Abatron BDI2000&lt;br /&gt;
* [http://www.amontec.com/index.shtml Amontec] JTAG Accelerator, Chameleon POD&lt;br /&gt;
* AZ-Electronics&lt;br /&gt;
* JtagConnection&lt;br /&gt;
* [http://www.lauterbach.de/mindex.html Lauterbach] Trace&lt;br /&gt;
* Macraigor Systems LLS&lt;br /&gt;
* Peedi&lt;br /&gt;
* Rowley Associates CrossConnect&lt;br /&gt;
&lt;br /&gt;
=== Anschlussbelegung ===&lt;br /&gt;
&lt;br /&gt;
Auf Evaluation-Boards verschiedener Hersteller (z.B. Atmel, IAR, Keil, Olimex) ist die JTAG-Schnittstelle über einen 20-poligen Wannenstecker (2*10, Raster 2,54mm) herausgeführt.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 | 1 Vcc  &lt;br /&gt;
 | 2 NC  &lt;br /&gt;
 |-&lt;br /&gt;
 | 3 nTRST&lt;br /&gt;
 | 4 GND &lt;br /&gt;
 |-&lt;br /&gt;
 | 5 TDI&lt;br /&gt;
 | 6 GND&lt;br /&gt;
 |-&lt;br /&gt;
 | 7 TMS&lt;br /&gt;
 | 8 GND&lt;br /&gt;
 |-&lt;br /&gt;
 | 9 TCK&lt;br /&gt;
 | 10 GND&lt;br /&gt;
 |-&lt;br /&gt;
 | 11 GND&lt;br /&gt;
 | 12 GND&lt;br /&gt;
 |-&lt;br /&gt;
 | 13 TDO&lt;br /&gt;
 | 14 GND&lt;br /&gt;
 |-&lt;br /&gt;
 | 15 NRESET/nSRST&lt;br /&gt;
 | 16 GND&lt;br /&gt;
 |-&lt;br /&gt;
 | 17 NC&lt;br /&gt;
 | 18 GND&lt;br /&gt;
 |-&lt;br /&gt;
 | 19 NC&lt;br /&gt;
 | 20 GND&lt;br /&gt;
 |-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Daneben existiert noch eine weniger gebräuchliche aber dokumentierte Variante mit 14 Polen (2*7). Bei fertigen Geräten, für die keine Schaltpläne vorliegen, muss man sich die herstellerspezifische Anschlussbelegung anhand des Datenblatts des verwendeten Controllers und mittels Messgerät selbst ermitteln.&lt;br /&gt;
&lt;br /&gt;
== MSP430 JTAG ==&lt;br /&gt;
&lt;br /&gt;
MSP430-JTAG für Parallelport: &lt;br /&gt;
* [http://elmicro.com/files/olimex/msp430-jtag-d.pdf Olimex MSP430 JTAG (PDF)] bzw. ([http://www.olimex.com/dev/images/msp430-jtag-d-sch.gif (GIF)]). Siehe auch Diskussion im [http://www.mikrocontroller.net/topic/57208#442620 Forum].&lt;br /&gt;
* [http://www.mikrocontroller.net/topic/90754#776070 Forumsbeitrag] mit Anhang eines chinesischen? Schaltplans (PDF)&lt;br /&gt;
&lt;br /&gt;
== FPGA JTAG ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.freewebs.com/lykos1986/cpldprogrammer.htm Xilinx JTAG programmer] ([[CPLD]], [[FPGA]])&lt;br /&gt;
* [http://www.embedded-projects.net/index.php?page_id=157 Xilinx JTAG XSVF Player mit USBprog] ([[CPLD]], [[FPGA]])&lt;br /&gt;
* [http://www.altera.com/literature/ug/ug_bbii.pdf ALTERA ByteBlaster]&lt;br /&gt;
* [http://www.pyroelectro.com/tutorials/byteblaster/index.html Build A ByteBlaster] bei www.pyroelectro.com&lt;br /&gt;
* [http://www.ixo.de/info/usb_jtag/ USB-JTAG-Adapter], kompatibel zu ALTERA USB-Blaster&lt;br /&gt;
* ColdFire BDM Pod&lt;br /&gt;
* [http://warmcat.com/milksop/cheaptag.html Cheaptag] - Xilinx Parallel Jtag programming cable&lt;br /&gt;
* FCPU-X Platform Cable USB JTAG cable&lt;br /&gt;
** Bezugsquelle (DE): [http://www.vht-impex-shop.de/product_info.php?info=p786_HW-USB-platform-cable--FCPU-X-platform-cable-similar-to-HW-USB-Kabel-for-Xilinx-evaluation-boards-etc-.html&amp;amp;XTCsid=e613a7119493deac52e83e9038ce131a http://www.vht-impex-shop.de]&lt;br /&gt;
** Bezugsquelle (US): [http://www.celeritous.com/estore/index.php?main_page=product_info&amp;amp;cPath=1&amp;amp;products_id=129 http://www.celeritous.com]&lt;br /&gt;
&lt;br /&gt;
= Software =&lt;br /&gt;
&lt;br /&gt;
== AVR JTAG ==&lt;br /&gt;
&lt;br /&gt;
* [[AVR-Studio]] (Windows)&lt;br /&gt;
* [[GDB]] in Verbindung mit [http://avarice.sourceforge.net/ AVaRICE] und AVR JTAGICE kompatibler Hardware. (Linux)&lt;br /&gt;
&lt;br /&gt;
== ARM JTAG ==&lt;br /&gt;
&lt;br /&gt;
* [[GDB]] bzw. Insight und auf die ARM JTAG Hardware abgestimmte GDB-Server (OCDRemote, [http://openocd.berlios.de/ OpenOCD], BDI2000, Peedi)&lt;br /&gt;
* [http://twentyone.bokee.com/ H-JTAG] und RDI-kompatible Debugger (SDT2.51, ADS1.2, RealView and IAR)&lt;br /&gt;
* Herstellerspezifische Software z.B. von Lauterbach&lt;br /&gt;
&lt;br /&gt;
== FPGA JTAG ==&lt;br /&gt;
&lt;br /&gt;
* Altera: Quartus Programmer (quartus_pgm)&lt;br /&gt;
* Lattice: ToDo...&lt;br /&gt;
* Xilinx: Impact, xc3sprog, ...&lt;br /&gt;
&lt;br /&gt;
== Allgemeine Tools ==&lt;br /&gt;
&lt;br /&gt;
* http://www.scanseer.com Boundary-scan pin probe tool&lt;br /&gt;
* http://www.ricreations.com/index.html TOP!&lt;br /&gt;
* http://www.rsn-tech.demon.co.uk/pjtag/pjtag.html Is bissel buggy, aber kleine Sachen gehen damit.&lt;br /&gt;
* http://urjtag.org Kommandozeilentool für Boundary Scan, FPGA und CPLD und Speicher lesen und schreiben u.v.a.m. (Nachfolger von openwince JTAG Tools)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:AVR]]&lt;br /&gt;
[[Kategorie:ARM]]&lt;br /&gt;
[[Kategorie:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30942</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30942"/>
		<updated>2008-09-09T11:03:33Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Icarus Verilog */  Tippfehler behoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um eine Kommandozeilen-basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der kompilierte Quellcode wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile auszuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt, das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instantiiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039;-File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039;-Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefiles sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav-File zu kreieren, in dem abgespeichert wird, welche Signale in der Anzeige gerade angezeigt werden. Startet man gtkwave mit diesem .sav-File bzw. lädt es später nach, wird die Anzeige wieder so dargestellt wie zu dem Zeitpunkt wenn das .sav-File erstellt wurde. Wird gtkwave nur mit einem .vcd-File gestartet, ist die Anzeige immer leer und die Signale müssen erst in die Anzeige gebracht werden. Wenn eine .sav-Datei vorhanden ist, dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30941</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30941"/>
		<updated>2008-09-09T10:53:24Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Parallele Prozesse mit join/fork */  Neuer Abschnitt über task und function&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Funktionsaufrufe mit function und task ==&lt;br /&gt;
&lt;br /&gt;
Analog zu Funktionen und Prozeduren in der Software-Programmierung stellt Verilog &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; zur Verfügung um komplexere Systeme in kleiner Einheiten aufzuteilen. Zu beachten ist das Verilog schon den &#039;&#039;module&#039;&#039;-Konstrukt für die Aufteilung hat. Aufrufe von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; können im Rahmen von &#039;&#039;initial&#039;&#039;-, bzw. &#039;&#039;always&#039;&#039;-Blöcken in &#039;&#039;module&#039;&#039;-Blöcken eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei wesentliche Unterschiede bei der Verwendung von &#039;&#039;function&#039;&#039; und &#039;&#039;task&#039;&#039; im Zusammenhang mit der Simulation:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;function&#039;&#039;&lt;br /&gt;
* der Aufruf liefert einen Rückgabewert&lt;br /&gt;
* es können keine Zeit- oder Ereignissteuerungen (#, @ und wait) eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;task&#039;&#039;&lt;br /&gt;
* der Aufruf liefert keinen Rückgabewert&lt;br /&gt;
* es können Zeit- oder Ereignissteuerungen eingesetzt werden&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30939</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30939"/>
		<updated>2008-09-09T10:31:36Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Hierarchie */  Tippfehler behoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instantiierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instantiieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instantiierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instantiierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instantiierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instantiiert werden kann die Parameterliste verändert und damit das instantiierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instantiiert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30864</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=30864"/>
		<updated>2008-09-05T12:46:38Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Zeit in der Simulation */  Formulierungsfehler behoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumpfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulation von großen Designs ist es sinnvoll die Anzahl der Signale die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden alle Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signale in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator arbeitet mit Simulationsschritte, die erst mal dimensionslos sind. Um dem Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer angegeben und können die Werte 1, 10, oder 100 haben.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung von &#039;&#039;`timescale&#039;&#039; verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren, erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt. D.h., nach einer Verzögerung von 10 sind auch 10 Simulationsschritte ausgeführt worden.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir den Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ns bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an, mit welcher Genauigkeit die Verzögerungsoperation erfolgt. Bisher haben wir ganzzahlige Werte verwendet. Für die Verzögerungsoperation können aber auch reale Zahlen verwendet werden. Die Simulationszeit wird errechnet, indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann, basierend auf der spezifizierten Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=FPGA&amp;diff=30452</id>
		<title>FPGA</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=FPGA&amp;diff=30452"/>
		<updated>2008-08-20T12:40:57Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Boards für Xilinx-FPGAs */  Preis vom FPGAz USBP geändert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;FPGA ist die Abkürzung für &amp;quot;&#039;&#039;&#039;F&#039;&#039;&#039;ield &#039;&#039;&#039;P&#039;&#039;&#039;rogrammable &#039;&#039;&#039;G&#039;&#039;&#039;ate &#039;&#039;&#039;A&#039;&#039;&#039;rray&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Aufbau ==&lt;br /&gt;
&lt;br /&gt;
=== Grundelemente  ===&lt;br /&gt;
Ein FPGA besteht, ähnlich wie ein [[CPLD]], aus vielen Logikelementen, hauptsächlich Flip-Flops (FF) und LUTs (LUT = Lookup-Table), die über elektronische &amp;quot;Schalter&amp;quot; entsprechend der vom Entwickler gewünschten Funktion miteinander verknüpft werden können.&lt;br /&gt;
&lt;br /&gt;
Eine &#039;&#039;&#039;LUT&#039;&#039;&#039; kann eine beliebige kombinatorische Funktion (NAND, XOR, AND, Multiplexer etc.) aus den Eingangssignalen realisieren. Die Anzahl der Eingangssignale pro LUT ist vom FPGA abhängig und liegt meist zwischen 4 und 6. Für Funktionen, die mehr Eingänge erfordern, als eine einzige LUT besitzt (hohes Fan-In), werden mehrere LUTs direkt miteinander verschaltet. Die &#039;&#039;&#039;Flip-Flops&#039;&#039;&#039; dienen dazu, Signalwerte zwischenzuspeichern, um sie im nächsten Takt weiterverarbeiten zu können. Das Verhältnis zwischen der Anzahl der LUTs und der Anzahl der Flip-Flops ist meist 1:1. Aktuelle FPGAs bestehen aus bis zu einigen zehntausend Logikelementen.&lt;br /&gt;
&lt;br /&gt;
Die logischen Schalter und Speicher sind in den meisten FPGAs durch SRAM-Speicherzellen realisiert, welche beim Bootprozess passend geladen werden. Das Laden dieser Konfigurationsdaten bzw. Verknüpfungsregeln geschieht dabei in der Regel aus einem speziellen Flash-ROM-Baustein heraus. Es kann aber auch ein Mikrocontroller benutzt werden. Die meisten (SRAM-basierten) FPGAs bieten daher für diesen Konfigurationsvorgang mehrere Modi (seriell, parallel, Master/Slave) an. Da die SRAM-Zellen ihren Inhalt beim Abschalten der Versorgungsspannung verlieren, muss ein SRAM-basierter FPGA bei jedem Einschalten neukonfiguriert werden. Daher benötigt ein solcher FPGA einige Millisekunden bis zur Betriebsbereitschaft.&lt;br /&gt;
&lt;br /&gt;
Eine FPGA-Familie beinhaltet Typen mit unterschiedlicher Anzahl und Komplexität von Logikzellen. So enthält ein Spartan3-1000 ca. 2,5 mal mehr Logik (FF, LUTs) als ein Spartan3-400.  &lt;br /&gt;
&lt;br /&gt;
FPGAs mit nichtflüchtigem Speicher basieren auf EEPROM-, Flash- (einige Familien von Lattice) oder AntiFuse- (Actel) Technologie. Die sogenannten AntiFuse FPGAs sind einmalig programmierbar.&lt;br /&gt;
&lt;br /&gt;
=== I/O Anschlüsse ===&lt;br /&gt;
FPGAs als universal einsetzbare Digital-ICs unterstützen eine Vielzahl von Signalstandards. Üblich sind verschiedene TTL-Pegel (5V, 3,3V, 2,5V), differentielle Signalstandards (LVDS, GTL) und im Hochpreisbereich serielle Standards bis zu 1 Gbps. Oftmals sind weitere Eigenschaften wie Treiberstärke und Flankensteilheit für jeden benutzerdefinierbaren Anschluss (User-IO) einstellbar. Meist sind die Pins in Bänke mit gleichem I/O Standard zusammengefasst. Innerhalb einer solchen Bank arbeiten alle Pins im gleichen I/O Standard und mit der selben I/O Spannung (H-Pegel).&lt;br /&gt;
&lt;br /&gt;
Ebenso können FPGA-interne Pull-Up und Pull-Down-Widerstände zugeschaltet werden, Terminierung wird ebenfalls unterstützt.&lt;br /&gt;
&lt;br /&gt;
Das I/O Verhalten wird mit den IO-Constraints in einem setting-File (Xilinx *.ucf, Altera *.acf) festgelegt.&lt;br /&gt;
&lt;br /&gt;
Einige Pins übernehmen zeitweilig oder allgemein besondere, nicht vom Anwender abschaltbare Funktionen. Darunter zählen die Pins zum Einlesen der Konfigurationsdaten. Oft sind einige wenige Pins (2 - 8) zum Einspeisen des Taktes für das Design reserviert.&lt;br /&gt;
&lt;br /&gt;
Die Hersteller bieten FPGAs mit gleicher Anzahl von Logikelementen in unterschiedlichen Gehäusen an. So kann der FPGA mit der passenden Anzahl von Pins eingesetzt werden. Das obere Ende markieren Chips mit über 1000 I/Os, die kleinsten bieten ca. 80(?) User-I/O. Oft werden nur BGA und QFP Gehäuse (bis ca. 240(?) Pins) angeboten.&lt;br /&gt;
&lt;br /&gt;
=== Komplexere Blöcke (Multiplizierer, RAM, PLL/DLL) ===&lt;br /&gt;
Neben den einfachen Flip-Flops beinhalten FPGAs darüber hinaus komplexe Routing- und Speicherkonfigurationsoptionen innerhalb und außerhalb der logischen Elemente (LEs), die es gestatten, komplexe Schalt- und Rechenstrukturen aufzubauen. Für rechenintensive Designs, z.B. in der Signalverarbeitung, enthalten viele FPGAs Multiplizierer direkt auf dem Chip, die in einem einzigen Taktzyklus Multiplikationen durchführen können.&lt;br /&gt;
&lt;br /&gt;
Ferner haben FPGAs oft einen von den LEs getrennt verfügbaren RAM-Bereich integriert, der sich in vielfältiger Weise ansprechen lässt. So können damit Single- oder Dualport-RAMs mit variabler Bitbreite erzeugt werden. Üblich sind mehrere (4 - 30) kleinere Dualport RAM-Blöcke von 4 - 16 kbit. Einige Familien besitzen einen größeren internen RAM, andere spezielle FIFO-Blöcke.&lt;br /&gt;
&lt;br /&gt;
Zur Generierung spezieller Takte sind PLL-Komponenten (phase locked loop) auf dem FPGA integriert. Einige Hersteller setzen mit dem selben Ziel DLL-Blöcke (delay locked loop) ein. Mittels dieser Blöcke können aus einem Taktsignal weitere erzeugt werden. Typisch sind Taktverdopplung oder -vervielfachung. Ebenso kann der Takt geteilt werden oder ein Signal gleicher Frequenz, aber um eine halbe, viertel usw. Periode verschoben erzeugt werden. Typische Anwendungen sind die Ansteuerung von DDR-RAMs oder die Kompensation von Laufzeitunterschieden zwischen Takt und mit diesem getakteten Steuersignalen. Meist sind 2 - 8 Taktnetzwerke und PLL/DLLs gleicher Anzahl integriert. Siehe auch [[Taktung FPGA/CPLD]].&lt;br /&gt;
&lt;br /&gt;
=== CPU im FPGA ===&lt;br /&gt;
&lt;br /&gt;
Programmierbare Prozessoren sind auch häufig bei FPGA Designs unverzichtbar. Diese sind zwar im Allgemeinen langsamer und weniger effizient als eine vollständige Implementation aus Logik-Primitiven -- aber auch deutlich &lt;br /&gt;
einfacher zu beherrschen. Insbesondere bei sequentiellen Aufgaben (Benutzerinterface, komplexe Steueraufgaben etc.) wird man gerne auf eine&lt;br /&gt;
klassische CPU zurückgreifen. &lt;br /&gt;
&lt;br /&gt;
Manche FPGAs integrieren einem oder mehrere Prozessorkerne (z.B. [[AVR]] bei Atmels FPSLIC, PowerPC bei Xilinx&#039; Virtex-4 oder ARM-Cortex-M1 bei IGLOO-FPGA von [http://www.actel.com actel]) als &#039;&#039;HardCores&#039;&#039; auf einem IC.&lt;br /&gt;
&lt;br /&gt;
Auf der anderen Seite gibt es auch &#039;&#039;SoftCores&#039;&#039;, Prozessorkerne die als Quelltext oder als vor-synthetisierte Netzliste vorliegen. In Abhänigkeit von den zur Verfügung stehenden Resourcen können diese &#039;&#039;SoftCores&#039;&#039; beliebig instantiiert werden. Es gibt eine Vielzahl verschiedener &#039;&#039;SoftCores&#039;&#039; -- &lt;br /&gt;
Teilweise kompatibel zu etablierten Prozessorarchitekturen (MIPS, SPARC, AVR), zum Teil optimiert auf die FPGAs einzelner Hersteller. Auch auf vergleichsweise &lt;br /&gt;
kleine aktuelle FPGAs kann man problemlos eine 32bit-RISC-CPU integrieren.&lt;br /&gt;
Unter [[FPGA Soft Core]] findet man eine Liste einiger weit verbreiteter &#039;&#039;SoftCores&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Als Programmspeicher werden die FPGA-internen RAM-Blöcke oder externe Speicher-ICs (SDRAM, SRAM) genutzt. Für einige Prozessorkerne stehen Hochsprachen wie C, C++ etc. zur Verfügung, andere werden in Assembler programmiert.&lt;br /&gt;
&lt;br /&gt;
== Eigenschaften ==&lt;br /&gt;
=== Geschwindigkeit ===&lt;br /&gt;
Die maximale „Geschwindigkeit“ eines FPGAs ist von der verwendeten Halbleitertechnologie (Prozess, Strukturgrößen), der internen Schaltungstopologie (Komplexität der LEs), Vorhandensein von harten Strukturen und vor allem vom Design abhängig. Dabei sind der sogenannte Datendurchsatz und die rein maximale Systemtaktfrequenz zu unterscheiden. Die erreichbare Taktfrequenz lässt sich ohne detaillierte Kenntnis des Designs nicht abschätzen, möglich sind je nach »Speed Grade« des ICs typischerweise Taktfrequenzen von 300-500 MHz für die Schaltgeschwindigkeit der reinen Logikelemente. Je nach der Anzahl und Komplexität der pro Takt durchzuführenden Operationen ergeben sich reale reale Systemtaktfrequenzen von meist 10-200 MHz. Maßgeblich ist, in wieweit das Design auf Fläche bzw. Geschwindigkeit hin optimiert und vom Tool synthetisiert wurde: Durch das Einbringen von zusätzlichen Registerstufen lassen sich z.B. zeitkritische Pfade entschärfen, sodass die Frequenz des Chips angehoben werden kann und der effektive Datendurchsatz trotz teilweise mehr CLKs zwischen Ein- und Ausgängen (Latenz) erhöht wird. Dieser lässt sich darüber hinaus durch die Nutzung paralleler Architekturen verbessern.&lt;br /&gt;
&lt;br /&gt;
Die Systemfrequenz kann-, muss aber nicht der Frequenz entsprechen, mit der Daten zyklisch eingetaktet und verarbeitet werden; zudem sind Schaltungsteile mit unterschiedlichen Taktfrequenzen zu unterscheiden: Mit einem Systemtakt1 von 20 MHz lassen sich z.B. 18-Bit AD-Wandler auslesen, die so z.B. alle 1 µs neue Daten liefern, die verarbeitet werden müssen. Bei der Nutzung von 5 solchen Wandlern, die sequentiell verarbeitet werden, lägen 5 MHz Datenfrequenz vor. Für andere Schaltungsteile, die z.B. asynchron an die Peripherie andocken, sowie reine »state machines« können Schaltungsteile auf der 2-4 fachen Frequenz betrieben werden.&lt;br /&gt;
&lt;br /&gt;
Generell sind Fläche und Geschwindigkeit konkurrierende Größen, zwischen denen ein Optimum gefunden werden muss. Für die preiswerten FPGA-Serien wie Spartan (Xilinx) und Cyclone (Altera) sind aufgrund technologischer Randbedingungen etwa 10-30% weniger Taktgeschwindigkeit bei gleichem Design zu erwarten, bzw. muss mit mehr Verbrauch an Logikelementen und Taktzyklen gerechnet werden (weniger Routingreserven, geringere Zahl von LUT-Eingängen, weniger hard-ressourcen). &lt;br /&gt;
&lt;br /&gt;
Identische Chips werden oft in 2 oder mehr Geschwindigkeitsklassen angeboten, die sich meist durch Bauteilselektion bei der Produktion ergeben. Grob kann man ca. 5%-10% höhere Taktung zwischen zwei Speedgrades erwarten.&lt;br /&gt;
&lt;br /&gt;
== Hersteller ==&lt;br /&gt;
Die größten Hersteller von FPGAs sind Altera und Xilinx. Weitere Hersteller sind Lattice, Actel und Atmel.&lt;br /&gt;
&lt;br /&gt;
* [http://www.altera.com Altera]&lt;br /&gt;
* [http://www.xilinx.com Xilinx]&lt;br /&gt;
* [http://www.lattice.com Lattice]&lt;br /&gt;
* [http://www.actel.com Actel]&lt;br /&gt;
&lt;br /&gt;
== Anwendung ==&lt;br /&gt;
&lt;br /&gt;
Der Aufbau komplizierter, applikationsnaher Strukturen wird meist durch automatische Routing- und Synthesewerkzeuge erledigt, welche mit einer logischen, funktionellen Beschreibung der Architektur in einer Hardwarebeschreibungssprache wie z.B. VHDL &amp;quot;gefüttert&amp;quot; werden. Die Hardwarebeschreibung in VHDL gelingt ihrerseits z.B. mit VHDL-generierenden Werkzeugen, mittels derer zuvor Logikstrukturen, hardwarenahe Strukturen, Ablaufdiagramme und Zustandsautomaten formuliert wurden.&lt;br /&gt;
&lt;br /&gt;
Durch die Standardisierung der Architektur einerseits und die Entkoppplung von applikationsorientierter Beschreibung sowie Chip- und Hersteller-spezifischer Synthese andererseits, wird die Hardware quasi als Software gebaut. Dies wiederum schafft alle Optionen der Wiederverwendung und Austausch von &amp;quot;Hardwareteilen&amp;quot;. So stehen inzwischen komplett nutzbare Schaltungen wie serielle Bausteine, RAM-Controller und vieles mehr als Open Source zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
== Entwicklungsboards und Starterkits ==&lt;br /&gt;
=== Boards für Xilinx-FPGAs ===&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; class=&amp;quot;sortable&amp;quot; id=&amp;quot;fpgaevalboards&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Bezeichn.&lt;br /&gt;
! Preis (&amp;amp;euro;)&lt;br /&gt;
! FPGA&lt;br /&gt;
! RAM (MByte)&lt;br /&gt;
! Flash (MByte)&lt;br /&gt;
! USB&lt;br /&gt;
! Ethernet&lt;br /&gt;
! RS-232&lt;br /&gt;
! µC&lt;br /&gt;
! Eingabe&lt;br /&gt;
! sonst.&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.knjn.com/board_Xylo.html Xylo-L]&lt;br /&gt;
| 130&lt;br /&gt;
| XC3S500E&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| 2.0&lt;br /&gt;
| 10base-T&lt;br /&gt;
| -&lt;br /&gt;
| LPC213x&lt;br /&gt;
| -&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| [http://www.xilinx.com/s3estarter Spartan3e Starter Kit]&lt;br /&gt;
| 180&lt;br /&gt;
| XC3S500E&lt;br /&gt;
| 64 MB DDR-SDRAM&lt;br /&gt;
| 16&lt;br /&gt;
| (JTAG)&lt;br /&gt;
| 10/100&lt;br /&gt;
| 2x&lt;br /&gt;
| -&lt;br /&gt;
| 4 Taster, 1 Drehgeber, 4 Schalter&lt;br /&gt;
| Coolrunner CPLD, LCD, 3-Bit VGA, PS/2&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.digilentinc.com/Products/Detail.cfm?Nav1=Products&amp;amp;Nav2=Programmable&amp;amp;Prod=S3BOARD Digilent Spartan-3]&lt;br /&gt;
| 100&lt;br /&gt;
| XC3S200/400/1000&lt;br /&gt;
| 1&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| 1x&lt;br /&gt;
| -&lt;br /&gt;
| 4 Taster, 8 Schalter&lt;br /&gt;
| VGA, PS/2, 7seg&lt;br /&gt;
|-&lt;br /&gt;
| [[Digilent Nexys]]&lt;br /&gt;
| 100&lt;br /&gt;
| XC3S200/400/1000&lt;br /&gt;
| 16&lt;br /&gt;
| 4&lt;br /&gt;
| 2.0&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| 4 Taster, 8 Schalter&lt;br /&gt;
| 7seg, Programmierung &amp;amp; Stromversorgung über USB&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.uxibo.de Uxibo]&lt;br /&gt;
| 88&lt;br /&gt;
| XC2S200E&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| 1.1&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| 4 Taster, 8 Schalter&lt;br /&gt;
| VGA I/O, Videomux, dual PS/2, 7seg, Buzzer, IOs auf Pinleisten, dual-channel FTDI2232C, 48 MHz + prog. Oszillator, Programmierung &amp;amp; Stromversorgung über USB&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.fpgaz.com/wiki/doku.php?id=fpgaz:usbp:hw FPGAz USBP]&lt;br /&gt;
| $135&lt;br /&gt;
| XC3S400&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| 2.0&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| Cypress FX2&lt;br /&gt;
| 2 Taster&lt;br /&gt;
| 8 LEDs, I2C-EEPROM&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.cesys.com/fpga/spartan/efm01_de.html EFM 01] Embedded FPGA Modul &lt;br /&gt;
| 145,-&lt;br /&gt;
| XC3S500E&lt;br /&gt;
| -&lt;br /&gt;
| 4&lt;br /&gt;
| 2.0&lt;br /&gt;
| -&lt;br /&gt;
| -&lt;br /&gt;
| FX-2&lt;br /&gt;
| -&lt;br /&gt;
| 28 x 44mm, 50 I/O auf 2.54mm Stiftleiste, WIN und LINUX Treiber&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Raggedstone 1 - Spartan-3 Development PCI-Karte ====&lt;br /&gt;
* Spartan-3 FPGA FG456-Package&lt;br /&gt;
* 32 bit, 33 MHz, 3.3/5V PCI interface&lt;br /&gt;
* 4Mbit Flash Memory&lt;br /&gt;
* 16KBit serielles EEprom&lt;br /&gt;
* 4 x 7 Segment Anzeigen LED, abnehmbar&lt;br /&gt;
* LM75 Temperatursensor&lt;br /&gt;
* viele DIL-Header für eigene Erweiterungen, verschiedene werden auch durch Hersteller angeboten&lt;br /&gt;
* 2 Drucktaster&lt;br /&gt;
* Mit dem PCI-Interface kann bei entsprechender Programmierung des FPGA auf den PCI-Bus eines Hostrechners zugegriffen werden, Beispieldesign unter http://projects.varxec.net/raggedstone1&lt;br /&gt;
* Webseite: http://www.enterpoint.co.uk/moelbryn/raggedstone1.html&lt;br /&gt;
* Preis mit XC3S400 ca. €145,- (inkl MWST)&lt;br /&gt;
* Preis mit XC3S1500 ca. €255,-  (inkl. MWST)&lt;br /&gt;
&lt;br /&gt;
==== LiveDesign Evaluation Board von Altium ====&lt;br /&gt;
* Kompatibel mit den LiveDesign-fähigen Entwicklungstools von Altium&lt;br /&gt;
* Xilinx-Version direkt mit ISE Webpack nutzbar&lt;br /&gt;
* Xilinx XC3S1000-4FG456C, wahlweise aber auch mit Altera EP1C12F324C8 (s.u.)&lt;br /&gt;
* Mit Flachbandkabel für PC-Verbindung (Druckerport) sowie weiteren Kabeln und Verbindern &lt;br /&gt;
* Peripherie: LEDs, Dip-Schalter, 6-stellige Siebensegmentanzeige, Taster, Stereo-DAC, zwei 256K x 16 RAMs&lt;br /&gt;
* &#039;&#039;kein&#039;&#039; on-board Flash RAM für FPGA-Konfiguration, diese muss nach dem Einschalten neu geladen werden&lt;br /&gt;
* Ports: PS2-Maus &amp;amp; -Tastatur, RS232, VGA (512 Farben), 2x18 IO-Pins für allgemeine Zwecke &lt;br /&gt;
* Listenpreis $99,- Endpreis: ~150 Euro (inkl. MwSt. und Versand)&lt;br /&gt;
&lt;br /&gt;
==== BurchED ====&lt;br /&gt;
http://www.burched.com/index.html&lt;br /&gt;
australischer Anbieter von Xilinx-Evaluationsboards&lt;br /&gt;
zur Zeit Webseite im Umbau&lt;br /&gt;
&lt;br /&gt;
==== Trenz-Electronic ====&lt;br /&gt;
http://www.trenz-electronic.de/products.html&lt;br /&gt;
* Kleines FPGA Board mit ucLinux und Virtex-II PowerPC, optional: ucLinux und Microblaze Softprozessor im Spartan-3 FPGA&lt;br /&gt;
* Spartan-3 FPGA Mikromodul mit 200K bis 1000K Systemgattern&lt;br /&gt;
* Pal/Gal kompatible FPGA und CPLD Module&lt;br /&gt;
&lt;br /&gt;
==== Simple-Solutions ====&lt;br /&gt;
http://www.simple-solutions.de/de/products/index.php&lt;br /&gt;
Mehrere Spartan3-FPGAs - Boards&lt;br /&gt;
&lt;br /&gt;
==== CESYS ====&lt;br /&gt;
http://www.cesys.com&lt;br /&gt;
&lt;br /&gt;
Cesys ist Entwickler und Hersteller von FPGA-boards mit Sitz in Deutschland.&lt;br /&gt;
&lt;br /&gt;
* Verschiedene FPGA boards mit USB, PCI und PCIe Schnittstellen im Lieferprogramm&lt;br /&gt;
* Je nach Ausführung mit Spartan-2/3/3E, Virtex2/2PRO/4&lt;br /&gt;
* verschiedene Speicherkonfigurationen (SO-DIMM, SRAM, SDRAM, DDR2)&lt;br /&gt;
&lt;br /&gt;
=== Boards für Altera-FPGAs ===&lt;br /&gt;
==== LiveDesign Evaluation Board von Altium ====&lt;br /&gt;
* Kompatibel mit den LiveDesign-fähigen Entwicklungstools von Altium&lt;br /&gt;
* * Wahlweise mit Altera EP1C12F324C8 oder Xilinx XC3S1000-4FG456C&lt;br /&gt;
* Mit Flachbandkabel für PC-Verbindung (Druckerport) sowie weiteren Kabeln und Verbindern &lt;br /&gt;
* Peripherie: LEDs, Dip-Schalter, 6-stellige Siebensegmentanzeige, Taster, Stereo-DAC, zwei 256K x 16 RAMs&lt;br /&gt;
* &#039;&#039;kein&#039;&#039; on-board Flash RAM für FPGA-Konfiguration, diese muss nach dem Einschalten neu geladen werden&lt;br /&gt;
* Ports: PS2-Maus &amp;amp; -Tastatur, RS232, VGA (512 Farben), 2x18 IO-Pins für allgemeine Zwecke &lt;br /&gt;
* Endpreis: ~150 Euro (inkl. MwSt. und Versand)&lt;br /&gt;
&lt;br /&gt;
==== Terasic TREX C1 Multimedia Development Kit ====&lt;br /&gt;
* Altera EP1C6Q240C8 &amp;amp; EP1S Serial Configuration Device&lt;br /&gt;
* Built-in USB Blaster programming circuitry (JTAG and AS mode)&lt;br /&gt;
* 1 MiB Flash Memory &amp;amp; 8 MiB SDRAM (1M x 4 x 16)&lt;br /&gt;
* CF Card Socket, 16-bit CD-quality Audio DAC&lt;br /&gt;
* TV Encoder, VGA, RS-232, PS/2, and more&lt;br /&gt;
* Many reference designs and C++ applications&lt;br /&gt;
* [http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&amp;amp;CategoryNo=39&amp;amp;No=14 www.terasic.com.tw]&lt;br /&gt;
* fertiger Core eines CPC6128 (8-Bit Homecomputer von 1984) für dieses Board, inlusive Sourcecode (eigener Z80 in AHDL, mit 24MHz eingesetzt): [http://www.symbos.de/trex.htm http://www.symbos.de/trex.htm]&lt;br /&gt;
* Listenpreis $149,-&lt;br /&gt;
&lt;br /&gt;
==== Altera Cyclone II 2C20 ====&lt;br /&gt;
* Altera Cyclone II EP2C20F484C7N FPGA mit 20000 LEs&lt;br /&gt;
* USB-BlasterTM download cable (integriert)&lt;br /&gt;
* EPCS4 serial configuration Flash&lt;br /&gt;
* 8-Mbyte SDRAM, 512-Kb SRAM, 4-Mbyte flash &lt;br /&gt;
* externer SMA - Clock-Eingang&lt;br /&gt;
* 24-bit Audio coder/decoder (CODEC) &lt;br /&gt;
* 10 Schalter, 4 Druckknöpfe inkl Reset &lt;br /&gt;
* 4St. 7-Segmentanzeigen, 10 rote LEDs + 8 grüne LEDs&lt;br /&gt;
* VGA, RS-232, and PS/2 Stecker&lt;br /&gt;
* Zwei 40-pin expansion ports + SD/MMC socket&lt;br /&gt;
* USB-Kabel, externes Steckernetztteil, CD-Rom&lt;br /&gt;
* Reference designs&lt;br /&gt;
* Qartus II Web Edition + NIOS II Web Edition&lt;br /&gt;
* http://www.altera.com/products/devkits/altera/kit-cyc2-2C20N.html&lt;br /&gt;
* Listenpreis $150,-&lt;br /&gt;
&lt;br /&gt;
==== Hpe Mini AC II - Altera Cyclone board von Gleichmann Research ====&lt;br /&gt;
* Altera Cyclone II EP2C35 FPGA (speed grade 6)&lt;br /&gt;
* Mit reprogrammierbarem Flash zur automatischen FPGA-Konfiguration&lt;br /&gt;
* 25 pin SUB-D connector (parallel) für direktes FPGA-Programmieren&lt;br /&gt;
* RS232 (9 pin SUB-D) &lt;br /&gt;
* VGA (15 pin SUB-D) mit 64 möglichen Farben&lt;br /&gt;
* Ethernet 10/100 Mbit/s, full/half duplex&lt;br /&gt;
* 1 USB 2.0 compatible full-speed target connector&lt;br /&gt;
* 3 USB 2.0 compatible full-speed host connectors&lt;br /&gt;
* Santa Cruz connector mit 40 nutzbaren I/Os&lt;br /&gt;
* Audio interface (line-in and line-out) mit CODEC&lt;br /&gt;
* SODIMM144 Sockel für (SDRAM) 256MB&lt;br /&gt;
* SDRAM-Speichersockel mit nur 32-Bit angebunden, die Hälfte des Speichers bleibt nicht nutzbar&lt;br /&gt;
* 25 MHz oscillator&lt;br /&gt;
* Prototyping area, Lötfläche&lt;br /&gt;
* 8 LEDs, grün, blau, 3x4 key matrix, 4-bit DIP switch&lt;br /&gt;
* LCD connector, 2-character 7-segment display&lt;br /&gt;
* Single step Knopf und Reset Knopf&lt;br /&gt;
* Parallelportkabel für PC&lt;br /&gt;
* Beispieldesign, Testprogramme, Datenblätter&lt;br /&gt;
* LEON3-CPU Design inkl. Source Code, Quartus IDE, SnapGear Linux&lt;br /&gt;
* Je nach Ausführung des Flashs €399,- bis €499,-&lt;br /&gt;
&lt;br /&gt;
==== Altera DE2 - Development and Education Board ====&lt;br /&gt;
* Altera Cyclone II 2C35 FPGA mit 35000 LEs&lt;br /&gt;
* Altera Serial Configuration devices (EPCS16) für Cyclone II 2C35&lt;br /&gt;
* USB Blaster board zur Programmierung und User API&lt;br /&gt;
* 8 MB SDRAM, 4 MB Flash Memory, 512KB SRAM&lt;br /&gt;
* SD Card Sockel, RS-232, Ethernet, 10-bit VGA, 24-bit Audio CODEC&lt;br /&gt;
* TV Decoder (NTSC/PAL), IrDA, USB (Host + Slave)&lt;br /&gt;
* Viele Besipiel mit Source Code wie TV, SD Music Player)&lt;br /&gt;
* [http://wwwab.fh-wedel.de/bause/handouts/vhdl/VhdlEinfuehrung.pdf Kleines aber nettes Tutorial zum Altera DE2 Dev. Board]&lt;br /&gt;
* Listenpreis US $495,-&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Cyclone III embedded Development Kit====&lt;br /&gt;
* Altera Cyclone III EP3C25 FPGA&lt;br /&gt;
* MiniSD-Card Sockel&lt;br /&gt;
* Audio Interface ADC CODEC&lt;br /&gt;
* 10/100 Mbit Fast Ethernet Schnittstelle&lt;br /&gt;
* FPGA-Konfiguration über USB&lt;br /&gt;
* NIOS II EVAL Lizenz&lt;br /&gt;
* IP LIB Altera&lt;br /&gt;
* Listenpreis US $495,-  ueber ALtera Webseite&lt;br /&gt;
&lt;br /&gt;
==== Cyclone II EP2C35 Entwicklungsboard ====&lt;br /&gt;
* Altera Cyclone II EP2C35-F672C8 FPGA mit 33.216 LEs&lt;br /&gt;
* Insgesamt 172 I/Os exklusiv verfügbar&lt;br /&gt;
* Bis zu 256 MByte SDRAM (SODIMM Speichermodul, 64-Bit Busanbindung)&lt;br /&gt;
* 16 MByte Flash (16-Bit Busanbindung)&lt;br /&gt;
* MiniSD-Card Sockel&lt;br /&gt;
* 10/100 Mbit Fast Ethernet Schnittstellenkontroller&lt;br /&gt;
* USB 2.0 high speed (480 Mbit) Schnittstellenkontroller&lt;br /&gt;
* FPGA-Konfiguration über USB&lt;br /&gt;
* Abmessungen: 96mm x 68mm&lt;br /&gt;
* Kompatibel mit der frei verfügbaren Altera Entwicklungssoftware&lt;br /&gt;
* http://www.fpga-dev.de/index.php?site=ep2c35_beschreibung&lt;br /&gt;
* wird in regelmässigen Abständen für 169,- Euro über ebay vertrieben (einfach nach &amp;quot;altera cyclone&amp;quot; suchen)&lt;br /&gt;
&lt;br /&gt;
==== NanoBoard-NB1 von Altium ====&lt;br /&gt;
* kompatibel mit den LiveDesign-fähigen Entwicklungstools von Altium&lt;br /&gt;
* Unterstützt eine breite Palette von Ziel-FPGAs durch Aufsteckplatinen &lt;br /&gt;
* Altera Cyclone (EP1C12-Q240C7) Aufsteckplatine enthalten &lt;br /&gt;
* Xilinx Spartan IIE (XC2S300E-PQ208) im Lieferumfang enthalten &lt;br /&gt;
* Enthält Stromversorgung mit verschiedenen Steckern für unterschiedliche Konfigurationen &lt;br /&gt;
* Mit Flachbandkabel für PC-Verbindung sowie weiteren Kabeln und Verbindern &lt;br /&gt;
* NanoBoard-NB1 Reference-Handbuch zur Hardware &lt;br /&gt;
* Peripherie: LCD, LEDs, Dip-Schalter, Tastenblock, Summer, ADC/DAC, 256K x 8 RAM, 8 MiB Serial Flash RAM, on-board Serial Flash RAM für FPGA-Konfig.&lt;br /&gt;
* Ports: PS2-Maus &amp;amp; -Tastatur, RS232, CAN, VGA, I2C, IO Stecker für allg. Zwecke &lt;br /&gt;
* Upgradefähige NanoBoard Controller Firmware &lt;br /&gt;
* Stabiler NanoBard-Sockel&lt;br /&gt;
* Listenpreis €995,-&lt;br /&gt;
=== Debugging-Hilfen ===&lt;br /&gt;
==== Core zum Debugging von Bussen von abaxor engineering ====&lt;br /&gt;
Durch die zunehmende Komplexität von FPGA-Designs gewinnt das Debugging von Busse zwischen Filtern und anderen Signalverarbeitungselementen, in Echtzeit immer mehr an Bedeutung. Die etablierten Werkzeuge der FPGA-Hersteller (ChipScope, SignalTap) bieten nicht genügend Speichertiefe, da sie auf im FPGA verfügbare Ressourcen bauen. Weiterhin begrenzt die JTAG-Schnittstelle die Bandbreite. Oft besteht aber die Notwendigkeit, Daten mit hoher Bandbreite zum PC zu übertragen. Der Zugang zum PC sollte keine zusätzlichen Treiber oder gar besondere Hardware benötigen, sondern über die vorhandenen Standard-Schnittstellen (USB, IDE, ATA, Ethernet) erfolgen. Da es sich um eine Debug-Funktion handelt, muss der Logikaufwand im FPGA gering sein. An dieser Stelle bietet sich die gut bewährte IDE (genauer ATA/ATAPI) Schnittstelle an. Mit Hilfe einer USB-IDE Bridge (USB-ATA) eröffnet sich die Möglichkeit zum Hot-Pluging, es ist noch nicht einmal erforderlich den Rechner zu öffnen.&lt;br /&gt;
&lt;br /&gt;
Der Core hat folgende Eigenschaften:&lt;br /&gt;
* Streaming der Daten zum PC mit mehr als 20 MByte/s&lt;br /&gt;
* keine Treiber im PC da Nutzung von Standardschnittstellen (USB oder IDE)&lt;br /&gt;
* Visualisierung mit beliebigen Programmen&lt;br /&gt;
* geringer Logikaufwand&lt;br /&gt;
&lt;br /&gt;
[http://www.abaxor.de/produkte.html abaxor.de-Webseite]&lt;br /&gt;
&lt;br /&gt;
==== open source Logikanalysator von sump.org====&lt;br /&gt;
Ein einfacher, übersichtlicher Logikanalysator findet sich auf sump.org. Er liegt im Quelltext vor wird mit ins Design einsynthetisiert. Als Speicher dient wahlweise SRAM oder intern RAM. Es können 32 Kanäle mit 100 MHz (oder weniger) gesampelt werden. Die Bediensoftware läuft platformunabhängig unter Java und benötigt eine serielle Schnittstelle (auch über USB-seriell Wandler) zum Core.&lt;br /&gt;
&lt;br /&gt;
[http://de.sump.org/projects/analyzer/ sump.org-Webseite]&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
* [[Hardwarebeschreibungssprachen]]&lt;br /&gt;
* [[Reset für FPGA/CPLD]]&lt;br /&gt;
* [[Taktung FPGA/CPLD]]&lt;br /&gt;
* Projekt [[Audio-DSP mit Spartan 3-FPGA]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [http://www.fpga4fun.com/index.html FPGA4Fun] - FPGA-Projekte, größtenteils mit Altera und Verilog&lt;br /&gt;
* [http://video.google.com/videoplay?docid=-4969729965240981475 Ein Vortrag, auf Englisch: General Purpose, Low Power Supercomputing Using Reconfiguration Logic]&lt;br /&gt;
* http://www.opencores.org - FPGA-Projekte, Opensource, jeder kann seine Eigen einstellen und an andere mitarbeiten. U.a. verschiede CPUs für FPGAs.&lt;br /&gt;
* http://members.optushome.com.au/jekent/FPGA.htm&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28620</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28620"/>
		<updated>2008-06-26T07:43:11Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Zeit in der Simulation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator hat die grundlegenden Simulationsschritte die erst mal Dimensionslos sind. Um den Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer-Wert angegeben und können die Werte 1, 10, oder 100 sein.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Zeiteinheit&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;Abkürzung&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir die Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ps bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an wie genau die Verzögerungsoperation genutzt werden. Bisher haben wir ganzzahlige Werte verwendet, für die Verzögerungsoperation können aber reale Zahlen verwendet werden. Die Simulationszeit wird errechnet indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann basierend auf der spezifizierte Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28619</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28619"/>
		<updated>2008-06-26T07:42:46Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Zeit in der Simulation */ Zeiten in Tabelle&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator hat die grundlegenden Simulationsschritte die erst mal Dimensionslos sind. Um den Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer-Wert angegeben und können die Werte 1, 10, oder 100 sein.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Zeiteinheit&lt;br /&gt;
|Abkürzung&lt;br /&gt;
|-&lt;br /&gt;
|Sekunden&lt;br /&gt;
|s&lt;br /&gt;
|-&lt;br /&gt;
|Millisekunden&lt;br /&gt;
|ms&lt;br /&gt;
|-&lt;br /&gt;
|Microsekunden&lt;br /&gt;
|us&lt;br /&gt;
|-&lt;br /&gt;
|Nanosekunden&lt;br /&gt;
|ns&lt;br /&gt;
|-&lt;br /&gt;
|Picosekunden&lt;br /&gt;
|ps&lt;br /&gt;
|-&lt;br /&gt;
|Femtosekunden&lt;br /&gt;
|fs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir die Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ps bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an wie genau die Verzögerungsoperation genutzt werden. Bisher haben wir ganzzahlige Werte verwendet, für die Verzögerungsoperation können aber reale Zahlen verwendet werden. Die Simulationszeit wird errechnet indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann basierend auf der spezifizierte Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28618</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28618"/>
		<updated>2008-06-26T07:40:34Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Zeit in der Simulation */ Doppeltes Icarus Kommando&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator hat die grundlegenden Simulationsschritte die erst mal Dimensionslos sind. Um den Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer-Wert angegeben und können die Werte 1, 10, oder 100 sein.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
&lt;br /&gt;
Zeiteinheit Abkürzung&lt;br /&gt;
Sekunden  s&lt;br /&gt;
Millisekunden ms&lt;br /&gt;
Microsekunden us&lt;br /&gt;
Nanosekunden ns&lt;br /&gt;
Picosekunden ps&lt;br /&gt;
Femtosekunden fs&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir die Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ns und entsprechend wartet die Simulation jetzt 100ps bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an wie genau die Verzögerungsoperation genutzt werden. Bisher haben wir ganzzahlige Werte verwendet, für die Verzögerungsoperation können aber reale Zahlen verwendet werden. Die Simulationszeit wird errechnet indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann basierend auf der spezifizierte Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28617</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28617"/>
		<updated>2008-06-26T07:38:42Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Zeit in der Simulation */ ps-&amp;gt;ns&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator hat die grundlegenden Simulationsschritte die erst mal Dimensionslos sind. Um den Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer-Wert angegeben und können die Werte 1, 10, oder 100 sein.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
&lt;br /&gt;
Zeiteinheit Abkürzung&lt;br /&gt;
Sekunden  s&lt;br /&gt;
Millisekunden ms&lt;br /&gt;
Microsekunden us&lt;br /&gt;
Nanosekunden ns&lt;br /&gt;
Picosekunden ps&lt;br /&gt;
Femtosekunden fs&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ns/1ns&#039;&#039;&#039; indem wir die Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvguenter@StCloud:~/tmp&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
guenter@StCloud:~/tmp&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheitenp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ps und entsprechend wartet die Simulation jetzt 100ps bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an wie genau die Verzögerungsoperation genutzt werden. Bisher haben wir ganzzahlige Werte verwendet, für die Verzögerungsoperation können aber reale Zahlen verwendet werden. Die Simulationszeit wird errechnet indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann basierend auf der spezifizierte Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28616</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28616"/>
		<updated>2008-06-26T07:37:27Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Zeit in der Simulation */ Neuer Abschnit mit join/fork&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator hat die grundlegenden Simulationsschritte die erst mal Dimensionslos sind. Um den Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer-Wert angegeben und können die Werte 1, 10, oder 100 sein.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
&lt;br /&gt;
Zeiteinheit Abkürzung&lt;br /&gt;
Sekunden  s&lt;br /&gt;
Millisekunden ms&lt;br /&gt;
Microsekunden us&lt;br /&gt;
Nanosekunden ns&lt;br /&gt;
Picosekunden ps&lt;br /&gt;
Femtosekunden fs&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ps/1ps&#039;&#039;&#039; indem wir die Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ns/1ns&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvguenter@StCloud:~/tmp&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
guenter@StCloud:~/tmp&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheitenp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ps und entsprechend wartet die Simulation jetzt 100ps bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Die Präzision gibt nun an wie genau die Verzögerungsoperation genutzt werden. Bisher haben wir ganzzahlige Werte verwendet, für die Verzögerungsoperation können aber reale Zahlen verwendet werden. Die Simulationszeit wird errechnet indem der Wert des Verzögerungsoperators mit der Zeiteinheit multipliziert wird und dann basierend auf der spezifizierte Präzision gerundet wird.&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;Zeiteinheit /&amp;lt;br&amp;gt; Präzision &#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungswert&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Verzögerungszeit&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3&lt;br /&gt;
|30ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/1ns&lt;br /&gt;
|#3.345&lt;br /&gt;
|33ns&lt;br /&gt;
|-&lt;br /&gt;
|10ns/100ps&lt;br /&gt;
|#3.345&lt;br /&gt;
|33.5ns&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parallele Prozesse mit join/fork ==&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28614</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28614"/>
		<updated>2008-06-26T06:34:28Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Verilog für Simulation */ Neuer Abschnitt über Zeit in der Simulation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
== Zeit in der Simulation ==&lt;br /&gt;
&lt;br /&gt;
Wenn wir im Zusammenhang mit der Simulation von Zeit gesprochen haben, dann bisher nur von Zeiteinheiten. Der Simulator hat die grundlegenden Simulationsschritte die erst mal Dimensionslos sind. Um den Verzögerungsoperator eine Dimension zu geben stellt Verilog die &#039;&#039;`timescale&#039;&#039; Anweisung zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&#039;&#039;`timescale&#039;&#039; 10ns / 1ns&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl bestimmt die Einheit für den Verzögerungsoperator. Die zweite Zahl die Auflösung mit der die Simulation durchgeführt wird. Beide Zahlen werden als Integer-Wert angegeben und können die Werte 1, 10, oder 100 sein.&lt;br /&gt;
&lt;br /&gt;
Als Zeiteinheiten werden die folgenden Werte unterstütz:&lt;br /&gt;
&lt;br /&gt;
Zeiteinheit Abkürzung&lt;br /&gt;
Sekunden  s&lt;br /&gt;
Millisekunden ms&lt;br /&gt;
Microsekunden us&lt;br /&gt;
Nanosekunden ns&lt;br /&gt;
Picosekunden ps&lt;br /&gt;
Femtosekunden fs&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel soll die Nutzung verdeutlichen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir den obigen Quellcode in eine Datei time.v packen und dann mit Icarus Verilog simulieren erhalten wir folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                  10 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Verzögerungsoperation von 10 Zeiteinheiten wird direkt umgesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt die Zeitskala verändern, z.B. nach &#039;&#039;&#039;`timescale 10ps/1ps&#039;&#039;&#039; indem wir die Code wie folgt ändern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
`timescale 10ps/1ps&lt;br /&gt;
&lt;br /&gt;
module test;&lt;br /&gt;
&lt;br /&gt;
initial begin&lt;br /&gt;
&lt;br /&gt;
  $display(&amp;quot;%t Start um 0&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  #10 $display(&amp;quot;%t Nach 10 Zeiteinheiten&amp;quot;, $time);&lt;br /&gt;
&lt;br /&gt;
  $finish();&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So erhalten wir mit der Simulation folgende Ausgabe:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
&amp;gt;vvp time.vvguenter@StCloud:~/tmp&amp;gt;iverilog -o time.vvp time.v&lt;br /&gt;
guenter@StCloud:~/tmp&amp;gt;vvp time.vvp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheitenp&lt;br /&gt;
                   0 Start um 0&lt;br /&gt;
                 100 Nach 10 Zeiteinheiten&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eine Zeiteinheit entspricht jetzt 10ps und entsprechend wartet die Simulation jetzt 100ps bevor die zweite &#039;&#039;$display&#039;&#039;-Anweisung ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28491</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28491"/>
		<updated>2008-06-18T19:06:32Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Verilog für Simulation */ Schreibfehler&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wie das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28483</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28483"/>
		<updated>2008-06-18T11:20:13Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Verilog für Simulation/Verifikation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation =&lt;br /&gt;
&lt;br /&gt;
Soweit haben wir die Sprache in Anlehnung an eine Programmiersprache beschrieben. Dabei sind schon einige Sonderheiten wie die Vierwertigkeit von &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; oder die Ereignissteuerung durch &#039;&#039;@&#039;&#039; im Zusammenhang mit der parallelen Abarbeitung von &#039;&#039;always&#039;&#039;, bzw. &#039;&#039;initial&#039;&#039; Blöcken erschienen. Auch hatten wir die Verzögerungsoperation &#039;&#039;#&#039;&#039; klammheimlich eingeführt, ohne wirklich tiefer darauf einzugehen wir das ganze im Hintergrund funktioniert.&lt;br /&gt;
&lt;br /&gt;
Der grundlegende Unterschied zwischen einer Programmiersprache und einer Hardwarbeschreibungssprache ist, das letztere ein Simulationsmodel zu Grunde liegt. In der Praxis sieht der Unterschied folgendermaßen aus. Bei einer compilierten Programmiersprache wird der Quellcode durch den Compiler in ein ausführbares Programm umgesetzt, das dann auf dem Computer ausgeführt werden kann. Bei der Hardwarebeschreibungssprache wird der Quellcode in eine für einen Simulator ausführbares Format umgewandelt. Nach dem Kompilieren kann dies dann mit dem Simulator ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden jetzt Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28475</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28475"/>
		<updated>2008-06-18T07:13:53Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Ereignissteuerung mit @ */  Kleine Umformulierung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, bei dessen Betätigung eine LED eingeschaltet wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von ein oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28474</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28474"/>
		<updated>2008-06-18T06:52:49Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Geschichte */  Link zur P1800 Arbeitsgruppe&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der [http://www.eda.org/sv-ieee1800/ IEEE P1800 Arbeitsgruppe] übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28373</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28373"/>
		<updated>2008-06-05T14:33:04Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* wire, reg; Datentypen */  Umformulierung, Erweiterung von Erklärungen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprache (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der IEEE P1800 Arbeitsgruppe übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== Datentypen: &#039;&#039;&#039;wire, reg&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Datentypen mit denen in Verilog modelliert wird, sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Wie ein Draht, kann aber ein &#039;&#039;wire&#039;&#039; keinen Signalzustand speichern. Für die Modellierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden und er findet damit als Signaltreiber Verwendung.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;assign&#039;&#039;-Anweisung kann als eine Art Verdrahtungsregel angesehen werden, mit der die Verbindung des &#039;&#039;wire&#039;&#039; beschrieben wird. Im obigen Beispiel werden die vier Drähte jeweils mit konstante Werte verdrahtet. Diese Konstanten sind die Signaltreiber für die Drähte.&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Blocks seine Werte zugewiesen bekommen. Mehr dazu in dem Abschnitt über &#039;&#039;initial&#039;&#039; und &#039;&#039;always&#039;&#039; Blöcke.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
== Schleifen mit for, while, und repeat ==&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten, bei denen eine Zählervariable nötig ist, stellte Verilog die &#039;&#039;for&#039;&#039;-Schleife zur Verfügung. Die einfache Anwendung erfolgt folgendermaßen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
  reg [3:0] mem[0:63];&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  for(i=0; i&amp;lt;64; i=i+1)&lt;br /&gt;
    mem[i] = 4&#039;d0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In dem Beispiel wird allen Speicherplätzen von &#039;&#039;&#039;mem&#039;&#039;&#039; der Wert 0 zugewiesen. Neu ist hier der Datentype &#039;&#039;integer&#039;&#039; der für die Zähler variable genutzt wird und laut Definition 32 Bit groß ist.&lt;br /&gt;
&lt;br /&gt;
Für die wiederholte Ausführung von Codesegmenten bei denen keine Zählervariable nötig ist kann der &#039;&#039;repeat&#039;&#039; Konstrukt genutzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  reg reset = 0;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  repeat(2) begin&lt;br /&gt;
&lt;br /&gt;
    #10 reset = 1;&lt;br /&gt;
    #10 reset = 0;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird zehn Zeiteinheiten gewartet und dann &#039;&#039;&#039;reset&#039;&#039;&#039; auf 1 gesetzt. Anschließend wieder 10 Zeiteinheiten gewartet und &#039;&#039;&#039;reset&#039;&#039;&#039; auf 0 gesetzt. Das ganze zwei mal wiederholt, so das ein doppelter &#039;&#039;&#039;reset&#039;&#039;&#039; Impuls entsteht.&lt;br /&gt;
&lt;br /&gt;
Eine bedingte Schleife kann mit &#039;&#039;while&#039;&#039; ausgeführt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  integer i;&lt;br /&gt;
&lt;br /&gt;
  while(i &amp;lt; 10) begin&lt;br /&gt;
    ...&lt;br /&gt;
    i = i + 1;&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Schleifenkörper wird solange ausgeführt so lange die Bedingung WAHR ist.&lt;br /&gt;
&lt;br /&gt;
== Parametrisierung durch Konstanten mit &#039;&#039;parameter&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir konstante Werte immer direkt in den Code eingeführt. Um Konstante Werte einheitlich über ein größeres Design zu verändern ist es sinnvoll für den Parameter einen einheitlichen Namen zu wählen und den Wert nur an einer Stelle im Design zu zu weisen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  parameter DW = 8;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  reg [DW-1:0] data_bus;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
Die Instanzierung kann jetzt noch durch die Überladung von &#039;&#039;parameter&#039;&#039; erweitert werden. Nehmen wir das vorherige Beispiel und schauen uns das &#039;&#039;module&#039;&#039; &#039;&#039;&#039;mux&#039;&#039;&#039; etwas näher an.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
module mux #(parameter DW=8)&lt;br /&gt;
            ( input [DW-1:0]  a, &lt;br /&gt;
              input [DW-1:0]  b, &lt;br /&gt;
              input           sel, &lt;br /&gt;
              output [DW-1:0] y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? a : b;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der &#039;&#039;module&#039;&#039; Definition wird jetzt noch eine Parameterliste vor die Portdefinition eingefügt, die mit dem Lattenzaun &#039;&#039;#&#039;&#039; gekennzeichnet ist. Dadurch ist es möglich die Parameter in der Portliste zu nutzen.&lt;br /&gt;
&lt;br /&gt;
Soll das Modul nun instanziert werden kann die Parameterliste verändert und damit das instanzierte Modul angepasst werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 &lt;br /&gt;
  parameter NeueDW=16;&lt;br /&gt;
&lt;br /&gt;
  wire [DW-1:0] w1;&lt;br /&gt;
  wire [DW-1:0] w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 #(.DW(NeueDW))( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 #(.DW(NeueDW))( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 #(.DW(NeueDW))( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Parameterüberladung erfolgt wie bei der expliziten Portverknüpfung in der Form &#039;&#039;&#039;.ZielParameter(NeuerParameter)&#039;&#039;&#039;. Im obigen Beispiel werden nun also drei Multiplexer mit der neuen Datenbreite von 16 Bit instanziert.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28353</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28353"/>
		<updated>2008-06-04T07:18:30Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Mehrwegeentscheidung mit case, casex, casez */ Abschnitt erweitert mit default case&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der IEEE P1800 Arbeitsgruppe übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00: dout = d0;&lt;br /&gt;
     2&#039;b01: dout = d1;&lt;br /&gt;
     2&#039;b10: dout = d2;&lt;br /&gt;
     2&#039;b11: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Entscheidungsliste größer und es müssen nicht immer alle Fälle behandelt werden. Dafür kann dann der &#039;&#039;default&#039;&#039; Konstrukt verwendet werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  reg        dout;&lt;br /&gt;
  wire       d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  always@(*)&lt;br /&gt;
   case (sel)&lt;br /&gt;
     2&#039;b00:   dout = d0;&lt;br /&gt;
     2&#039;b01:   dout = d1;&lt;br /&gt;
     2&#039;b10:   dout = d2;&lt;br /&gt;
     default: dout = d3;&lt;br /&gt;
   endcase&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für alle nicht gelisteten Ereignisse wird jetzt die Zuweisung für den &#039;&#039;default&#039;&#039; Fall durchgeführt.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28352</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28352"/>
		<updated>2008-06-03T18:49:21Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Entwicklung der Hardwarebeschreibungssprache */ Umformulierungen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der IEEE P1800 Arbeitsgruppe übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. So gibt es z.B. funktionale Programmiersprachen, wie C, bei denen teilt man mit Hilfe von Funktionsaufrufen große Problem in viele kleine Probleme. Bei objektorientierten Sprachen, wie z.B. C++, nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Modellierungsarten&lt;br /&gt;
&lt;br /&gt;
* Modellierung des Verhaltens (engl. Behavioral modeling)&lt;br /&gt;
* Modellierung auf Register-Transfer-Ebene (engl. Register-Transfer-Level  (RTL) modeling)&lt;br /&gt;
&lt;br /&gt;
Bei der Modellierung des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der RTL-Modellierung wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Der Verilog Standard IEEE 1394 hat dazu einen Zusatz, in dem ein einheitlicher synthesierbarer Syntax spezifiziert wird. Für eine spezielle Synthesesoftware bietet natürlich auch das entsprechende Benutzerhandbuch Aufschluss. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case, casex, casez ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  wire dout;&lt;br /&gt;
  wire d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  case (sel)&lt;br /&gt;
      2&#039;b00: dout = d0;&lt;br /&gt;
      2&#039;b01: dout = d1;&lt;br /&gt;
      2&#039;b10: dout = d2;&lt;br /&gt;
      2&#039;b11: dout = d3;&lt;br /&gt;
  endcase&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28351</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28351"/>
		<updated>2008-06-03T17:10:02Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Geschichte */ Erweitert mit System Verilog&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
Mit erscheinen des letzten Standards hat die [http://www.verilog.com/IEEEVerilog.html IEEE P1364 Arbeitsgruppe] ihre Arbeit eingestellt und die Pflege des Standards der IEEE P1800 Arbeitsgruppe übergeben, die sich mit der Standardisierung von System Verilog befasst.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case, casex, casez ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  wire dout;&lt;br /&gt;
  wire d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  case (sel)&lt;br /&gt;
      2&#039;b00: dout = d0;&lt;br /&gt;
      2&#039;b01: dout = d1;&lt;br /&gt;
      2&#039;b10: dout = d2;&lt;br /&gt;
      2&#039;b11: dout = d3;&lt;br /&gt;
  endcase&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28348</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28348"/>
		<updated>2008-06-02T11:45:48Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Geschichte */ LaTeX Fußnote ersetzt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 (&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby) als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case, casex, casez ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  wire dout;&lt;br /&gt;
  wire d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  case (sel)&lt;br /&gt;
      2&#039;b00: dout = d0;&lt;br /&gt;
      2&#039;b01: dout = d1;&lt;br /&gt;
      2&#039;b10: dout = d2;&lt;br /&gt;
      2&#039;b11: dout = d3;&lt;br /&gt;
  endcase&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:Verilog&amp;diff=28347</id>
		<title>Diskussion:Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:Verilog&amp;diff=28347"/>
		<updated>2008-06-02T11:39:53Z</updated>

		<summary type="html">&lt;p&gt;Guenter: Alte Diskussion gelöscht. Neue Diskussion über Style, Rechtschreibung und Übersetzung angefangen.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Das Dokument wächst langsam und es wird Zeit sich über einige Punkte Gedanken zu machen:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Fachbegriffe&#039;&#039;&#039; - Die Sprache habe ich auf Englisch gelernt, daher musste ich für Fachbegriffe erst die Deutsche Übersetzung finden, ohne wirklich zu wissen ob es der Treffende Begriff ist. Wenn für irgendwelche Begriffe ein Diskussionsbedarf bezüglich der Übersetzung besteht, sollter er hier stattfinden.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Schlüsselwörter&#039;&#039;&#039; der Sprache habe ich im Text recht konsequent immer Kursiv geschrieben. Namen die in Beispielen verwendet wurde habe ich nicht so konsequent in Fett geschrieben. Jetzt habe ich mir Gedanken darüber gemacht ob es nicht vielleicht sinnvoller ist es umgekehrt zu machen. Also die Namen Kursiv und die Schlüsselwörter Fett.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Rechtschreibung&#039;&#039;&#039; - Bei der Rechtschreibung habe ich teilweise die Englische Form der Getrenntschreibung angewendet, was im Deutschen so nicht richtig ist. Auch die Verbindung von Schlüsselwörtern mit Text ist wahrscheinlich nicht richtig, wie z.B. &#039;&#039;wire&#039;&#039; Konstrukt.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Guenter|Guenter]] 13:39, 2. Jun. 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Die alte Diskussion über Verilog habe ich gelöscht um hier Platz für Diskussion um den Artikel zu machen.&lt;br /&gt;
&lt;br /&gt;
Die alte Diskussion kann immer noch über den Link zur alten Version erreicht werden:&lt;br /&gt;
&lt;br /&gt;
http://www.mikrocontroller.net/wikisoftware/index.php?title=Diskussion:Verilog&amp;amp;oldid=28297&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Guenter|Guenter]] 13:39, 2. Jun. 2008 (CEST)&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28342</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28342"/>
		<updated>2008-06-02T09:59:09Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Entscheidungsoperation mit if-else und ? : */ Neuer Abschnitt case, casex, casez&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 \footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d0, d1, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d0 : d1;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== Mehrwegeentscheidung mit case, casex, casez ==&lt;br /&gt;
&lt;br /&gt;
Die Erweiterung der Entscheidungsoperation ist die Mehrwegeentscheidung, die mit &#039;&#039;case&#039;&#039; durchgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Um das vorherige Beispiel mit dem Multiplexer zu erweitern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  wire [1:0] sel;&lt;br /&gt;
  wire dout;&lt;br /&gt;
  wire d0, d1, d2, d3;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  case (sel)&lt;br /&gt;
      2&#039;b00: dout = d0;&lt;br /&gt;
      2&#039;b01: dout = d1;&lt;br /&gt;
      2&#039;b10: dout = d2;&lt;br /&gt;
      2&#039;b11: dout = d3;&lt;br /&gt;
  endcase&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden jetzt vier Eingangssignale in Abhängigkeit von &#039;&#039;sel&#039;&#039; auf den Ausgang gemultiplext.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28339</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28339"/>
		<updated>2008-06-02T09:48:34Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Logische Operationen */  Neuer Abschnitt über if-else, ?:&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
== Entscheidungsoperation mit if-else und ? : ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur die sequentielle Abarbeitung von Operationen besprochen. Oft ist es nötig, basierend auf Signalzustände verschiedene Blöcke abzuarbeiten. Der von Programmiersprachen bekannte &#039;&#039;if&#039;&#039; und &#039;&#039;else&#039;&#039; Konstrukt ist hierzu hilfreich und wird von Verilog unterstütz.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird in Abhängigkeit von einem &#039;&#039;&#039;reset&#039;&#039;&#039; Signal entweder der eine oder der andere Anweisungsblock ausgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  if(reset)&lt;br /&gt;
    dout &amp;lt;= 0;&lt;br /&gt;
  else&lt;br /&gt;
    dout &amp;lt;= din;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in dem obigen Beispiel &#039;&#039;&#039;reset&#039;&#039;&#039; 1 ist, dann wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert 0 zugewiesen. Ist &#039;&#039;&#039;reset&#039;&#039;&#039; 0 wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;din&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Sprachkonstrukt der Form &#039;&#039;if-else&#039;&#039; ist der Entscheidungsoperator &#039;&#039;?:&#039;&#039;, der auch von der Programmiersprache C bekannt ist. Er wird benutzt in der Form &#039;&#039;&#039;Test ? Wert_WAHR : Wert_FALSCH&#039;&#039;&#039;. &#039;&#039;&#039;Test&#039;&#039;&#039; kann hier eine logische Operation sein und wenn diese WAHR ist, dann wird &#039;&#039;&#039;Wert_WAHR&#039;&#039;&#039; zurück gegeben, andernfalls wird &#039;&#039;&#039;Wert_FALSCH&#039;&#039;&#039; zurück gegeben.&lt;br /&gt;
&lt;br /&gt;
Die Nutzung soll hier am Beispiel eines Multiplexers erläutert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 wire dout;&lt;br /&gt;
 wire d1, d2, sel;&lt;br /&gt;
 &lt;br /&gt;
 ...&lt;br /&gt;
 assign dout = sel ? d1 : d2;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;wire&#039;&#039; nehmen wir einen &#039;&#039;assign&#039;&#039; Konstrukt und die Zuweisung an &#039;&#039;&#039;dout&#039;&#039;&#039; hängt jetzt von dem &#039;&#039;&#039;sel&#039;&#039;&#039; Signal ab. Ist es 1, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d1&#039;&#039;&#039; zugewiesen. Ist &#039;&#039;&#039;sel&#039;&#039;&#039; 0, wird &#039;&#039;&#039;dout&#039;&#039;&#039; der Wert von &#039;&#039;&#039;d0&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28338</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28338"/>
		<updated>2008-06-02T09:21:46Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* always, initial */ Angepasst an Information aus dem neuen Abschnitt über die Ereignissteuerung. Erweitert mit der Beschreibung von zwei parallelen always Blöcke&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und die Ausführung endet dann nach dem Abarbeiten der letzten Operation.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem &#039;&#039;&#039;clk&#039;&#039;&#039; Signal das invertierte &#039;&#039;&#039;clk&#039;&#039;&#039; Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das &#039;&#039;&#039;clk&#039;&#039;&#039; Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von &#039;&#039;&#039;clk&#039;&#039;&#039; auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist &#039;&#039;&#039;clk&#039;&#039;&#039; undefiniert, also &#039;&#039;x&#039;&#039;, und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir die Ereignissteuerung kennen gelernte. Jetzt werden wir diese mit einem &#039;&#039;always&#039;&#039; kombinieren und damit steuern, wann der &#039;&#039;always&#039;&#039; Block durchlaufen werden soll.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039; und &#039;&#039;&#039;c&#039;&#039;&#039; wird &#039;&#039;&#039;y&#039;&#039;&#039; zugewiesen. Durch die Ereignissteuerung wird der &#039;&#039;always&#039;&#039; Block jedesmal durchlaufen, wenn sich der Signalzustand von &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, oder &#039;&#039;&#039;c&#039;&#039;&#039; geändert hat. D.h. wenn sich einer der Signalzustände ändert, wird die Zuweisung ausgeführt und &#039;&#039;&#039;y&#039;&#039;&#039; auf den neusten Stand gebracht. Danach wartet die Ausführung wieder bis sie durch die Ereignissteuerung ausgelöst wird. So viel sei vorweg genommen, diesen Konstrukt nennt man kombinatorische Logik und in dem Abschnitt über synthesierbare Logik wird noch mal näher darauf eingegangen.&lt;br /&gt;
&lt;br /&gt;
Seit Verilog 2001 kann die Ereignisliste auch vereinfacht werden und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wenn wir bisher von Signaländerungen im Zusammenhang mit der Ereignissteuerung gesprochen haben, dann sind wir immer davon ausgegangen das diese Änderung irgendwie von außen initiiert wurde. Gehen wir jetzt mal etwas mehr auf die parallele Beschreibung von Hardware ein und erweitern das vorherige Beispiel, um die Signaländerung mit in dem &#039;&#039;module&#039;&#039; auszuführen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y;&lt;br /&gt;
  reg a = 1;&lt;br /&gt;
  reg b = 1;&lt;br /&gt;
  reg c = 0;&lt;br /&gt;
&lt;br /&gt;
  always&lt;br /&gt;
    #10 c = ~c;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier haben wir jetzt zwei &#039;&#039;always&#039;&#039; Blöcke die in Parallel ausgeführt werden. Der erste &#039;&#039;always&#039;&#039; Block ist basiert auf dem Taktgenerator von zuvor. Eine kleine Abänderung ist, dass jetzt hier das Signal &#039;&#039;&#039;c&#039;&#039;&#039; an Stelle von clk alle 10 Zeiteinheiten in seinem Zustand geändert wird. Der Block hat keine Ereignissteuerung, er wird also ständig durchlaufen. Nur der &#039;&#039;&#039;#10&#039;&#039;&#039; Konstrukt hält ihn jeweils für 10 Zeiteinheiten an.&lt;br /&gt;
&lt;br /&gt;
Der zweite &#039;&#039;always&#039;&#039; Block wird wie vorher von der Ereignissteuerung immer dann ausgelöst, wenn sich eins der Signale in seiner Ereignisliste ändert. Hier haben wir &#039;&#039;&#039;a&#039;&#039;&#039; und &#039;&#039;&#039;b&#039;&#039;&#039; einen festen Wert zugewiesen. Das Signal &#039;&#039;&#039;c&#039;&#039;&#039; hingegen ändert sich ständig und löst die Ereignissteuerung und damit den Durchlauf des &#039;&#039;always&#039;&#039; Blockes aus. Die Zuweisung von &#039;&#039;&#039;y&#039;&#039;&#039; wird also immer dann auf den neusten Stand gebracht wenn sich &#039;&#039;&#039;c&#039;&#039;&#039; ändert.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28337</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28337"/>
		<updated>2008-06-02T08:23:47Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* @; Ereigniskontrolle */  --&amp;gt; Ereignissteuerung und weitere Umformulierung mit Erweiterung über posedge, negedge&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== Ereignissteuerung mit @ ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereignissteuerung, die durch das &#039;&#039;&#039;@&#039;&#039;&#039;-Zeichen beschrieben wird, lernen wir jetzt eine weitere kennen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereignissteuerung ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie bereits erwähnt wird die Ereignissteuerung mit dem Klammeraffen beschrieben.  Nach dem Klammeraffen folgt die Ereignisliste. Sie ist eingebettet in Klammern, eine Liste von einem oder mehreren Signalen, die bestimmen wann die folgende Operation ausgeführt wird. Im obigen Beispiel ist der &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;schalter&#039;&#039;&#039; in der Ereignisliste und bei einem Signalwechsel von diesem wird dem &#039;&#039;reg&#039;&#039; &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Neben Signaländerungen kann der Konstrukt auch genutzt werden um auf steigenden oder fallende Flanken zu reagieren. Hierzu werden die Schlüsselwörter &#039;&#039;posedge&#039;&#039; für steigende Flanke und &#039;&#039;negedge&#039;&#039; für fallende Flanke benutzt.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen wenn &#039;&#039;&#039;schalter&#039;&#039;&#039; einen Signalwechsel von 0 nach 1 oder 1 auf 0 macht. Soll das z.B. eingegrenzt werden und eine Zuweisung nur beim Wechsel von 0 auf 1 stattfinden, kann das Beispiel wie folgt geändert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module led_steuerung( input schalter );&lt;br /&gt;
&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
 @(posedge schalter) led = 1;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt wird die Zuweisung erst bei einer steigenden Flanke von &#039;&#039;&#039;schalter&#039;&#039;&#039; ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Die Ereignissteuerung ist einer der grundlegenden Sprachkonstrukte in der Hardwarebeschreibung um die parallele Natur der Hardware zu beschreiben. Im nächsten Abschnitt werden wir sie im Zusammenhang mit &#039;&#039;always&#039;&#039; Blöcken kennen lernen. Diese Blöcke erlauben es, parallel ablaufende Prozesse zu beschreiben und mit Hilfe der Ereignissteuerung deren Abläufe zu kontrollieren.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von sel entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28317</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28317"/>
		<updated>2008-05-31T12:34:25Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* wire, reg */  Neuer Abschnitt @ Ereigniskontrolle&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg; Datentypen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== @; Ereigniskontrolle ==&lt;br /&gt;
&lt;br /&gt;
Im vorherigen Abschnitt haben wir schon mit den Signalzuständen &#039;&#039;x&#039;&#039; und &#039;&#039;z&#039;&#039; eine Eigenart von [[Hardwarebeschreibungssprachen]] kennen gelernt. Mit der Ereigniskontrolle werden wir jetzt eine weitere kennen lernen. &lt;br /&gt;
&lt;br /&gt;
Mit der Ereigniskontrolle (@) ist es möglich den Zustand von einem Signal überwachen zu lassen und dann in Abhängigkeit davon eine Zuweisung auszulösen.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir als Beispiel einen Schalter, der eine LED steuert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 wire schalter;&lt;br /&gt;
 reg  led       = 0;&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
 @(schalter) led = 1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Ereigniskontrolle wird mit dem &#039;&#039;&#039;@&#039;&#039;&#039; Zeichen beschrieben. Im obigen Beispiel wird bei einem Signalwechsel von &#039;&#039;&#039;schalter&#039;&#039;&#039; dem &#039;&#039;&#039;led&#039;&#039;&#039; der Wert 1 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28316</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28316"/>
		<updated>2008-05-31T10:41:49Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Speicher Modellierung durch Felder */  Umformulierung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C sind z.B. Felder bekannt, um Elemente mit gleichem Datentyp zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird in die ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; geschrieben.&lt;br /&gt;
&lt;br /&gt;
Wird versucht von einem Speicherelement außerhalb des spezifizierten Indexbereiches zu lesen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28315</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28315"/>
		<updated>2008-05-31T10:37:49Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung */  Neuer Abschnitt für Speicher&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog &#039;&#039;&#039;Vektor&#039;&#039;&#039; genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;data&#039;&#039;&#039; wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von &#039;&#039;&#039;nibble&#039;&#039;&#039; erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird &#039;&#039;&#039;nibble&#039;&#039;&#039; zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== Speicher Modellierung durch Felder ==&lt;br /&gt;
&lt;br /&gt;
Mit der Modellierung von Speicher wird der Indizierung noch eins drauf gesetzt. Aus der Programmiersprache C z.B. werden Felder benutzt um Elemente gleichen Datentyps zusammen zu fassen. Der gleiche Konstrukt ist in Verilog möglich und wird z.B. zur Modellierung von Speicher genutzt.&lt;br /&gt;
&lt;br /&gt;
Mit dem folgenden Konstrukt z.B. wird ein 8 Bit breiter Speicher mit 64 Speicherzellen und der Bezeichnung &#039;&#039;&#039;meinMem&#039;&#039;&#039; definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] meinMem [0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich nur eine Verschmelzung von Vektor Definition (Bit breite vor Namen) mit Definition von Felder (Anzahl der Elemente nach Namen).&lt;br /&gt;
&lt;br /&gt;
Auf ein Element kann jetzt mit der bekannten Indizierung von Feldern zugegriffen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  meinMem[0] = 8&#039;h7f;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird der ersten Speicherstelle der hexadezimale Wert &#039;&#039;&#039;7f&#039;&#039;&#039; zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Wird versucht auf ein Speicherelement außerhalb des spezifizierten Indexbereiches zu zugreifen ist das Ergebnis &#039;&#039;x&#039;&#039;. Ein Schreibversuch auf ein Element außerhalb des spezifizierten Indexbereichs hat keine Auswirkung.&lt;br /&gt;
&lt;br /&gt;
Neben eindimensionalen ist auch möglich mehrdimensionale Speicher zu definieren wie z.B. mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg [7:0] zweiDmem [0:15][0:63];&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zum eindimensionalen Feld erfolgt der Zugriff mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  zweiDmem[0][7] = 8&#039;h2a;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28314</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28314"/>
		<updated>2008-05-31T09:53:50Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Gliederung */  Neue Formulierung und Schreibfehler behoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die [[Hardwarebeschreibungssprachen|Hardwarebeschreibungssprache]] Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache für Simulation und Synthese zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Konstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur die Teile der Sprache zu besprechen, die für Neueinsteiger(innen) erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vorgezogen, da es hier keine Beschränkungen in der Nutzung der Sprache und der Art der Modellierung gibt. Auch ist es der Teil, bei dem erste praktische Erfolge mit dem Simulator erzielt werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil in dem die synthesierbaren Konstrukte der Sprache erläutert werden.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28307</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28307"/>
		<updated>2008-05-30T20:00:32Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* $monitor */  Beschreibung erweitert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wird das folgende Beispiel simuliert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module monitor_tb;&lt;br /&gt;
&lt;br /&gt;
 reg clk    = 0;&lt;br /&gt;
 reg reset  = 0;&lt;br /&gt;
&lt;br /&gt;
 initial&lt;br /&gt;
   $monitor(&amp;quot;Zeit: %t Takt: %b reset: %b&amp;quot;, $time, clk, reset);&lt;br /&gt;
&lt;br /&gt;
 always&lt;br /&gt;
   #10 clk =~clk;&lt;br /&gt;
&lt;br /&gt;
 initial begin&lt;br /&gt;
   $display(&amp;quot;Kleiner $monitor test&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   #15 reset = 1;&lt;br /&gt;
   #22 reset = 0;&lt;br /&gt;
&lt;br /&gt;
   #10 $display(&amp;quot;#%0t Fertig&amp;quot;, $time);&lt;br /&gt;
   $finish;&lt;br /&gt;
&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erhält man folgenden Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
Kleiner $monitor test&lt;br /&gt;
Zeit:                    0 Takt: 0 reset: 0&lt;br /&gt;
Zeit:                   10 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   15 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   20 Takt: 0 reset: 1&lt;br /&gt;
Zeit:                   30 Takt: 1 reset: 1&lt;br /&gt;
Zeit:                   37 Takt: 1 reset: 0&lt;br /&gt;
Zeit:                   40 Takt: 0 reset: 0&lt;br /&gt;
#47 Fertig&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Zeitpunkt 0 wird der &#039;&#039;$display&#039;&#039; Task ausgeführt und druckt den Text &#039;&#039;&#039;&amp;quot;Kleiner $monitor test&amp;quot;&#039;&#039;&#039; aus. Alle Signale sind zu dem Zeitpunkt auf 0 und der &#039;&#039;$monitor&#039;&#039; Task druckt zum ersten mal den Signalzustand aus.&lt;br /&gt;
&lt;br /&gt;
Der nächste Aufruf erfolgt wenn clk nach 10 Zeiteinheiten seinen Zustand wechselt. Dieser Wechsel wird autonom in dem &#039;&#039;always&#039;&#039; Block alle 10 Zeiteinheiten durchgeführt. Parallel dazu wird in dem &#039;&#039;initial&#039;&#039; Block nach 15 Zeiteinheiten der reset auf 1 gesetzt. Dazwischen kommt wieder der Wechsel von clk, der um 20 auf 0 und um 30 wieder auf 1 gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Im &#039;&#039;initial&#039;&#039; Block wird reset 22 Zeiteinheiten nach dem Setzen wieder zurück gesetzt. Das Setzen fand um 15 statt, plus 22 Zeiteinheiten, somit wird reset um 37 zurück gesetzt. Dann folgt noch mal ein clk Wechsel, bevor die Simulation um 47 beendet wird. Zu der Zeit findet kein Signalwechsel mehr statt, so das der &#039;&#039;$monitor&#039;&#039; Task nicht mehr aufgerufen wird. So haben wir vor dem &#039;&#039;$finish&#039;&#039; Task noch mal einen &#039;&#039;$display&#039;&#039; Task gesetzt, der die Zeit mit dem Wort &#039;&#039;&#039;&amp;quot;Fertig&amp;quot;&#039;&#039;&#039; ausdruckt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28306</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28306"/>
		<updated>2008-05-30T19:27:10Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* $finish */  Neuer Abschnitt $dumpfile, $dumpvars&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
=== $dumpfile, $dumpvars ===&lt;br /&gt;
&lt;br /&gt;
Ein Value Change Dump (VCD) Files ist ein text basiertes File in dem Signalzustandsänderungen von der Simulation geschrieben werden. Die Datei kann dann z.B. von einem Programm eingelesen und dargestellt werden. Ein solches Programm ist z.B. [http://home.nc.rr.com/gtkwave/ gtkwave].&lt;br /&gt;
&lt;br /&gt;
Der Simulator generiert in der Regel so ein VCD File nicht von selbst, sondern muss dazu instruiert werden. Eine Form die von Simulatoren unterstützt wird ist durch die beiden Verilog System Tasks &#039;&#039;$dumpfile&#039;&#039; und &#039;&#039;$dumvars&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top_tb;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
    $dumpfile(&amp;quot;top_tb.vcd&amp;quot;);&lt;br /&gt;
    $dumpvars(0, top_tb);&lt;br /&gt;
  end&lt;br /&gt;
  ...&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit &#039;&#039;$dumfile(&amp;quot;top_tb.vcd&amp;quot;)&#039;&#039; wird der Dateiname des VCD Files spezifiziert. Gerade bei der Simulatin von großen Designs ist es sinnvoll die Anzahl der Signal die in das Dumpfile geschrieben werden zu beschränken. Der &#039;&#039;$dumpvars&#039;&#039; System Task erlaubt dazu die Hierarchieebene mit zu spezifizieren. Mit dem Befehl &#039;&#039;$dumpvars(0, top_tb)&#039;&#039; werden all Signale von der spezifizierten Ebene an nach unten in das Dumpfile geschrieben. Sollen z.B. nur die Signal in top_tb in das Dumpfile geschrieben werden, dann kann dies mit der Ebene 1, also &#039;&#039;$dumpvars(1, top_tb)&#039;&#039; beschränkt werden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28304</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28304"/>
		<updated>2008-05-30T18:59:15Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Icarus Verilog */ Weitere Erläuterung des Makefile&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Doolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;Makefile&#039;&#039;&#039; besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel ist eine Datei &#039;&#039;&#039;foo.v&#039;&#039;&#039; vorhanden die ein Modul von &#039;&#039;&#039;bar.v&#039;&#039;&#039; instanziiert. Die Testbench ist in der Datei &#039;&#039;&#039;foo_tb.v&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Das Projekt wird compiliert und simuliert mit dem Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_check&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Vorausgesetzt das [http://home.nc.rr.com/gtkwave/ gtkwave] installiert ist, kann im Zusammenhang mit einem generierten &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile und einem &#039;&#039;&#039;foo.sav&#039;&#039;&#039; File dieses mit folgendem Kommando aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; make foo_view&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; Dumpfile erhält man durch folgenden Konstrukt in der Testbench:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
 initial begin&lt;br /&gt;
   $dumpfile(&amp;quot;foo.vcd&amp;quot;);&lt;br /&gt;
   $dumpvars (0, foo_tb);&lt;br /&gt;
 end&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu diesem Aufruf des Makefile sei noch folgende Anmerkung gemacht. Der normale Aufruf von &#039;&#039;&#039;foo.vcd&#039;&#039;&#039; mit gtkwave erfolgt folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Kommando hätte keinen Vorteil gegenüber &#039;&#039;&#039;make foo_view&#039;&#039;&#039;. Mit gtkwave ist es nun möglich ein sogenanntes .sav File zu kreieren, in dem abgespeichert wird welche Signale in der Anzeige sind. Wenn diese Datei vorhanden ist dann muss gtkwave wie folgt aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; gtkwave foo.vcd foo.sav&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Behält man nun diese Datei als Teil des Projektes, ist es möglich beim nächsten mal mit &#039;&#039;&#039;make foo_view&#039;&#039;&#039; die gleiche Ansicht wieder zu erhalten.&lt;br /&gt;
&lt;br /&gt;
Das ursprüngliche Makefile von Larry Doolittle hatte noch einen Test mit [http://de.wikipedia.org/wiki/Awk awk], der das Testergebnis an das Makefile zurück gibt. Den Test habe ich herausgenommen, da der Aufwand meines Erachtens größer als der Nutzen war.&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28302</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28302"/>
		<updated>2008-05-30T17:30:57Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Icarus Verilog */  Nutzung mit Makefile&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Dokumentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando &#039;&#039;iverilog&#039;&#039; verwendet. Mit dem -o Parameter spezifiziert man den Namen der Ausgabedatei.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Kompilierte Code wird dann mit der Applikation &#039;&#039;vvp&#039;&#039; simuliert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für größere Projekte ist ein sinnvoller Einsatz den Aufruf durch ein Makefile durchzuführen. Im Mai 2008 hat Larry Dolittle auf der gEDA users mailing list ein Makefile zur Verfügung gestellt das hier folgend beschrieben werden soll.&lt;br /&gt;
&lt;br /&gt;
Das Makefile besteht aus einem allgemeinen Teil der sich nicht ändert und einem projektspezifischen Teil in dem die Abhängigkeiten für das spezielle Projekt festgelegt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;c&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# Hier werden die Abhängigkeiten festgelegt&lt;br /&gt;
#&lt;br /&gt;
foo_tb: foo.v bar.v&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Allgemeiner Teil der sich nicht ändert&lt;br /&gt;
#&lt;br /&gt;
%_tb: %_tb.v&lt;br /&gt;
	iverilog -Wall -DSIMULATE ${VFLAGS_$@} $^ -o $@&lt;br /&gt;
#&lt;br /&gt;
# Generic regression test&lt;br /&gt;
%_check: %_tb testcode.awk&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
%.vcd: %_tb&lt;br /&gt;
	vvp $&amp;lt;&lt;br /&gt;
#&lt;br /&gt;
# Useful for those testbenches that have a corresponding .sav file&lt;br /&gt;
%_view: %.vcd %.sav&lt;br /&gt;
	gtkwave $^&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
clean:&lt;br /&gt;
	rm -f *_tb *.vcd&lt;br /&gt;
&amp;lt;/c&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28301</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28301"/>
		<updated>2008-05-30T16:12:24Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Icarus Verilog */ Beispiel der Nutzung hinzugefügt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
Basierend auf dem Beispiel von der [http://iverilog.wikia.com/wiki/Getting_Started  Icarus Verilog Documentation] nehmen wir das &amp;quot;Hallo Welt&amp;quot; Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module main;&lt;br /&gt;
  initial &lt;br /&gt;
    begin&lt;br /&gt;
      $display(&amp;quot;Hallo, Welt&amp;quot;);&lt;br /&gt;
      $finish;&lt;br /&gt;
    end&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Kompilieren wird das Kommando:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt; iverilog -o main.vvp main.v&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Simulieren gibt man dann ein:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;gt; vvp main.vvp&lt;br /&gt;
Hallo Welt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28300</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28300"/>
		<updated>2008-05-30T16:03:26Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Open-Source Simulatoren */ Abschnitt mit Informationen über Icarus Verilog erweitert&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
Für Verilog gibt es die folgenden Simulatoren als Open-Source:&lt;br /&gt;
&lt;br /&gt;
*[http://icarus.com/eda/verilog/ Icarus Verilog]&lt;br /&gt;
*[http://www.pragmatic-c.com/gpl-cver/ CVER]&lt;br /&gt;
&lt;br /&gt;
Im folgenden wird etwas näher auf die Nutzung mit Icarus Verilog eingegangen.&lt;br /&gt;
&lt;br /&gt;
== Icarus Verilog ==&lt;br /&gt;
&lt;br /&gt;
Icarus Verilog ist eine Simulations- und Synthese-Software für Verilog. Bei der Software handelt es sich um Kommandozeilen basierte Applikationen. In diesem Abschnitt werden wir uns auf die Funktion als Simulator beschränken.&lt;br /&gt;
&lt;br /&gt;
Die Funktion ist verteilt auf die zwei Applikationen:&lt;br /&gt;
&lt;br /&gt;
* iverilog  (Compiler)&lt;br /&gt;
* vvp       (Simulator)&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28299</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28299"/>
		<updated>2008-05-30T15:53:52Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Entwicklung der Hardwarebeschreibungssprache */  Noch ein Typo gefunden&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Structural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
*http://icarus.com&lt;br /&gt;
*http://www.pragmatic-c.com/gpl-cver/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28298</id>
		<title>Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Verilog&amp;diff=28298"/>
		<updated>2008-05-30T15:52:35Z</updated>

		<summary type="html">&lt;p&gt;Guenter: /* Entwicklung der Hardwarebeschreibungssprache */  Schreibfehler behoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einleitung =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Verilog ist eine Hardwarebeschreibungssprace (Hardware Description Language: HDL) die es ermöglicht ein digitales System in einem recht weiten Spektrum an Abstraktion zu spezifizieren.&lt;br /&gt;
&lt;br /&gt;
== Geschichte ==&lt;br /&gt;
Verilog wurde im Winter 1983/84 /footnote{&amp;quot;The Verilog Hardware&lt;br /&gt;
Description Language&amp;quot;, Thomas &amp;amp; Moorby} als ein proprietäres&lt;br /&gt;
Produkt zur Verifikation und Simulation von digitaler Logik entwickelt.&lt;br /&gt;
&lt;br /&gt;
Verilog wurde erstmals vom [http://ieee.org IEEE] 1995 standardisiert in IEEE 1364-1995.&lt;br /&gt;
Eine Erweiterung wurde dann 2001 durchgeführt mit IEEE 1364-2001 und&lt;br /&gt;
später IEEE 1364-2005.&lt;br /&gt;
&lt;br /&gt;
== Entwicklung der Hardwarebeschreibungssprache ==&lt;br /&gt;
&lt;br /&gt;
Das Besondere an einer Hardwarebeschreibungssprache sind die zwei unterschiedlichen Ansätze mit der die Sprache eingesetzt wird. Bei einer Programmiersprache gibt es den Sprachsyntax und in Abhängigkeit der Sprache gibt es eine Philosophie wie diese Sprache und alle verfügbaren Konstrukte eingesetzt werden. Also z.B. gibt es funktionale Programmiersprache, wie z.B. C, bei der mit Hilfe von Funktionsaufrufen ein großes Problem in viele kleine Probleme unterteilt wird. Bei Objekt orientierten Sprachen wie z.B. C++ nimmt man Objekte und unterteil ein Problem in die verschieden Objekte und wie diese miteinander kommunizieren.&lt;br /&gt;
&lt;br /&gt;
[Hardwarebeschreibungssprachen]] wurden ursprünglich zur Spezifikation und Verifikation mit einem Simulator entwickelt. In diesem Bereich kann man auch den gesamten Syntax der Sprache einsetzen. Unterschieden werden die beiden Arten&lt;br /&gt;
&lt;br /&gt;
* Simulation des Verhaltens (Behavioral Simulation)&lt;br /&gt;
* Simulation der Struktur (Sturctural Simulation)&lt;br /&gt;
&lt;br /&gt;
Beim Simulieren des Verhaltens werden oft noch keine zeitlichen Aspekte verwendet. Es geht darum in einer abstrakten Form die Funktion des zu entwickelten digitalen Schaltkreises zu simulieren.&lt;br /&gt;
&lt;br /&gt;
Mit der strukturellen Simulation wird dann das Design takt genau simuliert.&lt;br /&gt;
&lt;br /&gt;
Später dann kamen einige Electronic Design Automation (EDA) - Firmen auf die Idee, eine Hardwarebeschreibungssprache nicht nur für die Simulation, sondern auch für die Synthese der eigentlichen Hardware zu benutzen. Für diesen Ansatz waren aber die [[Hardwarebeschreibungssprachen]] viel zu mächtig und so wurden nur einfache Sprachkonstrukte genommen, die das Synthesetool unterstützt.&lt;br /&gt;
&lt;br /&gt;
Aus dieser Entwicklung heraus haben sich die beiden Sichtweisen einer Hardwarebeschreibungssprache für Simulation und Synthese entwickelt. Ein Benutzer muss also immer im Hinterkopf haben, welchen Teil der Sprache er für seine Entwicklung nutzen kann. Für die Simulation sind in der Regel keine Grenzen gesetzt. Für die Entwicklung synthesierbarer Logik dagegen sind nur einige Sprachkonstrukte erlaubt. Aufschluss darüber welche das sind findet man am Besten in dem Benutzerhandbuch des jeweiligen Synthesetools. Für Xilinx ist das z.B. das [http://www.google.de/search?q=xilinx+xst+user+guide XST User&#039;s Guide].&lt;br /&gt;
&lt;br /&gt;
== Gliederung ==&lt;br /&gt;
&lt;br /&gt;
Dieser Artikel gibt eine Einführung in die Hardwarebeschreibungssprache Verilog, mit der Zielsetzung, ein Verständnis für die unterschiedliche Nutzung der Sprache, wie z.B. für Simulation oder Synthese, zu geben.&lt;br /&gt;
&lt;br /&gt;
Der Artikel gliedert sich in die drei Teile:&lt;br /&gt;
&lt;br /&gt;
* Sprachübersicht&lt;br /&gt;
* Simulation/Verifikation&lt;br /&gt;
* Synthesierbare Kunstrukte&lt;br /&gt;
&lt;br /&gt;
In der Sprachübersicht werden einige grundlegende Sprachelemente vermittelt. Dieser Teil ist bewusst klein gehalten und versucht nur diese Teile der Sprache zu besprechen, die für jemanden der Verilog neu lernt erst mal wichtig sind.&lt;br /&gt;
&lt;br /&gt;
Daran schließt sich ein Teil mit dem Schwerpunkt der Simulation/Verifikation synthesierbarer Logik. Zwar wissen wir an der Stelle noch nicht viel von synthesierbarer Logik, dieser Teil wurde aber bewusst vor der synthesierbaren Logik gesetzt, da er weniger Restriktionen bezüglich benutzbarer Sprachkonstrukte hat. Auch ist es der Teil, bei dem als erstes einige praktische Erfolge mit der Simulation gewonnen werden.&lt;br /&gt;
&lt;br /&gt;
Darauf folgt dann der Teil mit den synthesierbaren Konstrukten.&lt;br /&gt;
&lt;br /&gt;
= Sprachübersicht =&lt;br /&gt;
&lt;br /&gt;
== module ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegende Gruppierung wird in Verilog durch &#039;&#039;module&#039;&#039; durchgeführt. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
// Einzeiliger Kommentar, wie C++&lt;br /&gt;
&lt;br /&gt;
module MeinModulName ( input a, output b, inout data);&lt;br /&gt;
&lt;br /&gt;
/* Mehrzeiliger Kommentar&lt;br /&gt;
   Wie von C bekannt&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Signale werden durch Ports dem Modul übergeben. Für Signale in das Modul&lt;br /&gt;
gibt es den &#039;&#039;input&#039;&#039; Port. Ausgänge werden durch &#039;&#039;output&#039;&#039;&lt;br /&gt;
spezifiziert und ein bidirektionaler Bus durch &#039;&#039;inout&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Wie oben gezeigt sind ein- oder mehrzeilige Kommentar wie bei C/C++ möglich.&lt;br /&gt;
&lt;br /&gt;
== wire, reg ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden Signale in Verilog sind &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039;. Analog zum elektrischen Draht können mit dem &#039;&#039;wire&#039;&#039; Verbindungen durchgeführt werden. Für die Modulierung digitaler Logik ist es aber auch nötig Signaltreiber zu haben. Hier kommt der Datentyp &#039;&#039;reg&#039;&#039; ins Spiel. Mit ihm können Signalzustände gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die Signalzustände:&lt;br /&gt;
&lt;br /&gt;
* 0 --&amp;gt; logisch null&lt;br /&gt;
* 1 --&amp;gt; logisch eins&lt;br /&gt;
* z --&amp;gt; hochohmig&lt;br /&gt;
* x --&amp;gt; undefiniert&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können die Signalzustände wie folgt einem &#039;&#039;wire&#039;&#039; zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  wire a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  assign a = 0;&lt;br /&gt;
  assign b = 1;&lt;br /&gt;
  assign c = x;&lt;br /&gt;
  assign d = z;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit dem &#039;&#039;assign&#039;&#039; Konstrukt können nur einem &#039;&#039;wire&#039;&#039; Signale zugewiesen werden. Ein &#039;&#039;reg&#039;&#039; muss innerhalb eines &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block seine Werte zugewiesen bekommen.&lt;br /&gt;
&lt;br /&gt;
== always, initial ==&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;always&#039;&#039; und &#039;&#039;initial&#039;&#039; Blöcke werden verwendet um die parallele Natur von Hardware zu beschreiben. Jeder dieser Blöcke wird parallel ausgeführt, wobei ein &#039;&#039;initial&#039;&#039; Block nur einmal durchlaufen wird und ein &#039;&#039;always&#039;&#039; Block, wie eine Endlosschleife, ständig wiederholt wird.&lt;br /&gt;
&lt;br /&gt;
Nehmen wir mal einen &#039;&#039;initial&#039;&#039; Block als Beispiel und kommen auf das vorherige Problem zurück, dass einem &#039;&#039;reg&#039;&#039; nur in einem &#039;&#039;always&#039;&#039; oder &#039;&#039;initial&#039;&#039; Block Werte zugewiesen werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg a, b, c, d;&lt;br /&gt;
&lt;br /&gt;
  initial begin&lt;br /&gt;
&lt;br /&gt;
    a = 0;&lt;br /&gt;
    b = 1;&lt;br /&gt;
    c = z;&lt;br /&gt;
    d = x;&lt;br /&gt;
&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was in dem Beispiel neu dazu gekommen ist, ist die Gruppierung durch &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039;. Vergleichbar mit den geschweiften Klammern in der Programmierung mit C/C++, können Segmente mit &#039;&#039;begin&#039;&#039; und &#039;&#039;end&#039;&#039; zusammengefasst werden.&lt;br /&gt;
&lt;br /&gt;
Im obigen Beispiel wird der &#039;&#039;initial&#039;&#039; Block einmal durchlaufen und im Falle einer Simulation würde diese dann weiterlaufen ohne das irgend welche weiteren Zuweisungen erfolgen.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;initial&#039;&#039; Konstrukt wird vorwiegend in der Simulation für Testbenches verwendet. In der Beschreibung synthesierbarer Logik findet er weniger Verwendung.&lt;br /&gt;
&lt;br /&gt;
Der &#039;&#039;always&#039;&#039; Konstrukt kann sowohl in Testbenches als auch in synthesierbarer Logik verwendet werden. Hier erst mal ein Beispiel aus einer Testbench zum Generieren eines Taktsignals:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
reg clk = 0;&lt;br /&gt;
&lt;br /&gt;
always&lt;br /&gt;
  #10 clk = ~clk;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als neuer Sprachkonstrukt kommt hier das Verzögerungszeichen &#039;&#039;#&#039;&#039;, das die Ausführung in diesen Fall für 10 Zeiteinheiten anhält und dann mit der Ausführung des ihm folgenden Konstrukts weiter fortfährt. Was also in dem &#039;&#039;always&#039;&#039; Block geschieht ist, dass die Simulation für 10 Zeiteinheiten angehalten wird und dann dem clk Signal das invertierte clk Signal zugewiesen wird. Der &#039;&#039;always&#039;&#039; Block toggelt also das clk Signal alle 10 Zeiteinheiten.&lt;br /&gt;
&lt;br /&gt;
Die anfängliche Initialisierung von clk auf 0 ist sehr wichtig, da das Toggeln nur von 0 auf 1, bzw. 1 auf 0 funktioniert. Wird sie weggelassen ist clk undefiniert, also &#039;x&#039; und das Toggeln würde nicht funktionieren.&lt;br /&gt;
&lt;br /&gt;
Vielleicht ist es ganz sinnvoll an dieser Stelle noch mal zu erwähnen, dass das Verzögerungszeichen nicht synthesierbar ist.&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt jetzt noch mal einen synthesierbaren Konstrukt mit dem &#039;&#039;always&#039;&#039; Block, bei dem die Ausführung durch eine sensitivity Liste gesteuert wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module;&lt;br /&gt;
&lt;br /&gt;
  reg y, a, b, c;&lt;br /&gt;
&lt;br /&gt;
  always @(a, b, c)&lt;br /&gt;
    y = a &amp;amp; b &amp;amp; c;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die logische UND Verknüpfung von a, b und c wird y zugewiesen. Seit Verilog 2001 kann man die Liste vereinfachen und einfach durch (*) ersetzen. Der Konstrukt heißt dann also &#039;&#039;&#039;always @(*)&#039;&#039;&#039;. Die sensitivity Liste gibt an, welche Signale auf Veränderung überwacht werden. Hat sich eins der Signal verändert, wird der &#039;&#039;always&#039;&#039; Block durchlaufen und das Ergebnis y auf den neusten Stand gebracht.&lt;br /&gt;
&lt;br /&gt;
== Hierarchie ==&lt;br /&gt;
&lt;br /&gt;
Um ein komplexeres Design zu kreieren ist die Instanzierung von Modulen sehr hilfreich. Nehmen wir das Modul &#039;&#039;module mux(input a, input b, input sel, ouput y)&#039;&#039;, ohne genauer auf dessen Innenleben einzugehen, und instanzieren es mehrmals in dem &#039;&#039;module top(...)&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module top (input a, &lt;br /&gt;
            input b, &lt;br /&gt;
            input c, &lt;br /&gt;
            input d,&lt;br /&gt;
            input s1,&lt;br /&gt;
            input s2,&lt;br /&gt;
            input s3,&lt;br /&gt;
            output y);&lt;br /&gt;
&lt;br /&gt;
  wire w1, w2;&lt;br /&gt;
&lt;br /&gt;
  mux m1 ( .a(a),  .b(b),  .sel(s1), .y(w1) );&lt;br /&gt;
  mux m2 ( .a(c),  .b(d),  .sel(s2), .y(w2) );&lt;br /&gt;
  mux m3 ( .a(w1), .b(w2), .sel(s3), .y(y)  );&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Verknüpfung findet statt durch die explizite Nennung der Ports. Der Port von dem instanzierten Modul wird in der Form &#039;&#039;&#039;.PortName()&#039;&#039;&#039; geschrieben. Das Signal mit dem er verknüpft wird schreibt man in die Klammern des Ports. Mit der Verknüpfung &#039;&#039;&#039;.y(w1)&#039;&#039;&#039; wird also der Ausgangsport &#039;&#039;&#039;y&#039;&#039;&#039; von der Instanz &#039;&#039;&#039;m1&#039;&#039;&#039; des Modules &#039;&#039;&#039;mux&#039;&#039;&#039; mit dem &#039;&#039;wire&#039;&#039; &#039;&#039;&#039;w1&#039;&#039;&#039; im Modul &#039;&#039;&#039;top&#039;&#039;&#039; verknüpft.&lt;br /&gt;
&lt;br /&gt;
Eine andere Variante der Verknüpfung wird durch die Position der Ports in der Definition des Modules erreicht. In unserem Fall ist Port a der erste Port, also wird der &#039;&#039;wire&#039;&#039; der an erste Stelle bei der Instanzierung geschrieben wird, mit Port a des Moduls verbunden. Das vorherige Beispiel wird in diesem Fall dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  mux m1 ( a,  b,  s1, w1 );&lt;br /&gt;
  mux m2 ( c,  d,  s2, w2 );&lt;br /&gt;
  mux m3 ( w1, w2, s3, y  );&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Vorteil ist, dass hier nicht noch explizit der Port des Modules genannte werden muss. Das wird jedoch schnell unübersichtlich mit Modulen, die eine lange Portliste haben.&lt;br /&gt;
&lt;br /&gt;
== Skalar, Vektor, Bit-Splitting, Verkettung, Wiederholung ==&lt;br /&gt;
&lt;br /&gt;
Bisher haben wir nur einfache Signal genutzt, d.h. Signale die ein Bit breit sind. Ein Bus aus &#039;&#039;wire&#039;&#039; z.B. wird in der Form &#039;&#039;wire [msb:lsb] &amp;lt;wire_name&amp;gt;&#039;&#039; spezifiziert und wird in Verilog Vektor genannt. Entsprechend kann auch ein &#039;&#039;reg&#039;&#039; Vektor spezifiziert werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [15:0] data;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data[0]   = 1;        // Setzt nur Bit 0&lt;br /&gt;
&lt;br /&gt;
  data[15:13] = 3&#039;b110;   // Setzt Bits 15, 14 = 1, Bit 13 = 0, Wert ist binär&lt;br /&gt;
  data[13:11] = 3&#039;d2;     // Setzt Bits 13-11, Wert ist dezimal&lt;br /&gt;
  data[10:1]  = 9&#039;h0a;    // Setzt Bits 10-1, Wert ist hexadezimal&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Beispiel zeigt wie ein 16 Bit breiter Vektor spezifiziert wird und anschließend einzelne Bits davon gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
Bei der Zuweisung wird hier erstmals bei Werten die Bitbreite spezifiziert und verschiedene Zahlenrepräsentationen verwendet. Die Bitbreite wird in der Form &#039;&#039;&#039;&amp;lt;Zahl&amp;gt;&amp;lt;Hochkomma&amp;gt;&#039;&#039;&#039; spezifiziert. Für die verschiedenen Zahlenformate gibt es die Buchstaben &#039;&#039;b, d, h&#039;&#039;, die für binär, dezimal, bzw. hexadezimal stehen.&lt;br /&gt;
&lt;br /&gt;
Aufmerksamen Lesern ist vielleicht aufgefallen, dass die Art der Zuweisung eigentlich in einen &#039;&#039;initial&#039;&#039; oder &#039;&#039;always&#039;&#039; Block hätte gepackt werden müssen um so zu funktionieren. Eine andere Möglichkeit währe ein &#039;&#039;assign&#039;&#039; Konstrukt daraus zu machen. Aus Übersichtlichkeit wurde hierbei darauf verzichtet.&lt;br /&gt;
&lt;br /&gt;
In diesen Zusammenhang passt es auch die Verkettung von Signalen zu erklären. Sie wird mit geschweiften Klammern erreicht:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  wire [7:0] data;&lt;br /&gt;
  wire [3:0] nibble;&lt;br /&gt;
&lt;br /&gt;
  ...&lt;br /&gt;
  data = {4&#039;b0000, nibble}; &lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dem &#039;&#039;wire&#039;&#039; data wird ein 8 Bit breites Wort zugewiesen, bei dem die oberen 4 Bit auf Null gesetzt sind und die unteren 4 Bit den Signalzustand von nibble erhalten.&lt;br /&gt;
&lt;br /&gt;
Die Wiederholung wird auch mit geschweifter Klammer beschrieben und hat die Form &#039;&#039;&#039;{r{num}}&#039;&#039;&#039;. Hierbei wird num, r mal wiederholt.&lt;br /&gt;
&lt;br /&gt;
Um bei dem letzten Beispiel zu bleiben, eine Abänderung bei der die oberen 4 Bit nicht auf Null gesetzt werden, sondern auch den Signalzustand von nibble erhalten kann folgendermaßen erreicht werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  data = {2{nibble}};&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird nibble zwei mal wiederholt und damit auf 8 Bit Länge gebracht.&lt;br /&gt;
&lt;br /&gt;
== =, &amp;lt;=; blockierende und nicht-blockierende Zuweisung ==&lt;br /&gt;
&lt;br /&gt;
In Verilog gibt es die zwei Zuweisungsarten:&lt;br /&gt;
&lt;br /&gt;
* =&lt;br /&gt;
* &amp;lt;=&lt;br /&gt;
&lt;br /&gt;
Erstere wird als blockierende Zuweisung (blocking assignment) bezeichnet. Letztere als nicht-blockierend (nonblocking assignment).&lt;br /&gt;
&lt;br /&gt;
Im Standard werden die folgenden zwei Richtlinien für deren Verwendung gegeben:&lt;br /&gt;
&lt;br /&gt;
* (=) Benutze blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die kombinatorische Logik modellieren.&lt;br /&gt;
* (&amp;lt;=) Benutze nicht-blockierende Zuweisungen in &#039;&#039;always&#039;&#039; Blöcken die sequentielle Logik modellieren.&lt;br /&gt;
&lt;br /&gt;
Nähere Details über den Hintergrund können in dem Artikel [http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf &amp;quot;Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!&amp;quot;, Cliff Cummings, SNUG 2000] nachgelesen werden.&lt;br /&gt;
&lt;br /&gt;
== Logische Bit-Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die grundlegenden logischen Bit-Operation sind:&lt;br /&gt;
&lt;br /&gt;
*| --&amp;gt; OR&lt;br /&gt;
*&amp;amp; --&amp;gt; AND&lt;br /&gt;
*~ --&amp;gt; NOT&lt;br /&gt;
*^ --&amp;gt; XOR&lt;br /&gt;
&lt;br /&gt;
Sie werden erweitert durch:&lt;br /&gt;
*~&amp;amp; --&amp;gt; NAND&lt;br /&gt;
*~| --&amp;gt; NOR&lt;br /&gt;
*^~ oder ~^ --&amp;gt; XNOR&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt einen sogenannten Reduktions-Operator, bei dem mit&lt;br /&gt;
einem Operator mehrere Signale zusammen geführt werden. Damit kann z.B.&lt;br /&gt;
eine logische AND-Verknüpfung von 8 Signalen wie folgt durchgeführt&lt;br /&gt;
werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module MeinUnd8 (  input   [7:0] a,&lt;br /&gt;
                   output        y);&lt;br /&gt;
&lt;br /&gt;
  assign y = &amp;amp;a;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Arithmetische Operationen, signed, $signed ==&lt;br /&gt;
&lt;br /&gt;
Bevor wir kurz über die grundlegenden arithmetischen Operationen sprechen kehren wir noch mal zu den Datentypen &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; zurück. Diese werden in Verilog als vorzeichenlos, also &#039;&#039;&#039;unsigned&#039;&#039;&#039; angesehen.&lt;br /&gt;
&lt;br /&gt;
Entsprechend folgen arithmetische Operationen mit &#039;&#039;wire&#039;&#039; und &#039;&#039;reg&#039;&#039; dem Modulo 2^n, wobei n die Bitbreite des Vektors ist.&lt;br /&gt;
&lt;br /&gt;
Verilog unterstützt die bekannten arithmetischen Operation:&lt;br /&gt;
&lt;br /&gt;
* +&lt;br /&gt;
* -&lt;br /&gt;
* *&lt;br /&gt;
* /&lt;br /&gt;
&lt;br /&gt;
Mit der entsprechend bekannten Präzedenz das Multiplikation und Division vor Addition und Subtraktion geht. Für Klarheit können, wie so oft bei Programmiersprachen, Operationen mit Klammern gruppiert werden.&lt;br /&gt;
&lt;br /&gt;
Leider unterstützt Verilog nicht eine Vereinfachung, die z.B. von der Programmiersprache C bekannt ist, bei der die Zuweisung und der Operator zusammengeschrieben werden und damit ein Operand eingespart werden kann.&lt;br /&gt;
&lt;br /&gt;
Die Schreibweise:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
a = a + 12;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
Kann also nicht abgekürzt werden. Auch ist kein Inkrement oder Dekrement Operator bekannt. In &#039;&#039;for&#039;&#039; Schleifen ist es also immer nötig zu schreiben:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
i=i+1;&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um jetzt auch mit 2&#039;s Komplement zahlen rechnen zu können wird der Konstrukt &#039;&#039;signed&#039;&#039; benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erinnern wir uns das es sich um Modulo 2^n Arithmetik handelt. Im dem Fall wo a als signed spezifiziert wird, ist der Zahlenbereich von a [-8 .. 7]. Für den Fall von b ist er [0..15] und damit entsteht für 2-4 ein Unterlauf und die Berechnung ist 15-2.&lt;br /&gt;
&lt;br /&gt;
In diesem Zusammenhang ist es wichtig zu betrachten was passiert wenn bei arithmetischen Operation gemischte Operanten, also einer ist unsigned der andere signed, genommen werden. &#039;&#039;&#039;Eine Operation zwischen einem signed und einem unsigned Datentyp resultiert in einen unsigned Datentyp.&#039;&#039;&#039; Da dieses Verhalten nicht immer gewünscht ist, gibt es die $signed() System Funktion. Auf System Funktionen und System Tasks wird später noch näher eingegangen.&lt;br /&gt;
&lt;br /&gt;
Um jetzt eine arithmetische Operation mit a und b aus dem vorherigen Beispiel durchzuführen und das Ergebnis auch als signed zu haben, muss der unsigned Operand erst mit $signed() in einen signed gewandelt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  reg signed [3:0] a;&lt;br /&gt;
  reg        [3:0] b;&lt;br /&gt;
  reg signed [4:0] c;&lt;br /&gt;
&lt;br /&gt;
  a = 2 - 4;          // a = -2&lt;br /&gt;
  b = 2 - 4;          // b = 13&lt;br /&gt;
&lt;br /&gt;
  c = a + $signed(b);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Vergleichs Operationen; ==, ===, !=, !==, &amp;lt;, &amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Analog zu anderen Programmiersprachen stellt Verilog die Vergleichsoperatoren ==, !=, &amp;lt;, &amp;gt; zur Verfügung. Erinnern wir uns aber daran das ein Signal neben 0 und 1 auch noch die Zustände x oder z annehmen kann. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eine Vergleichsoperation bei der ein Bit den Zustand x oder z hat, ist im Ergebnis x und das wird als FALSCH angesehen.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 == 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx == 4&#039;b11xx;    // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z == 4&#039;b110z;    // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im gleichen Sinn werden größer oder kleiner Operationen immer FALSCH wenn ein x oder z Zustand vorhanden ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 &amp;gt; 4&#039;b11xx;      // = x --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b110z &amp;gt; 4&#039;b1100;      // = x --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um einen exakten Vergleich durch zu führen gibt es den sogenannten case equality operator (===). Hier werden auch die Zustände x und z mit in den Vergleich einbezogen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  4&#039;b1100 === 4&#039;b1100;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b1100 === 4&#039;b11xx;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
  4&#039;b11xx === 4&#039;b11xx;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110z === 4&#039;b110z;    // = 1 --&amp;gt; WAHR&lt;br /&gt;
  4&#039;b110x === 4&#039;b110z;    // = 0 --&amp;gt; FALSCH&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Logische Operationen ==&lt;br /&gt;
&lt;br /&gt;
Die im letzten Abschnitt beschriebenen Vergleichsoperationen können mit logischen Operationen Verknüpft werden. Wie von den gängigen Programmiersprachen unterstützt Verilog die logischen Operationen:&lt;br /&gt;
&lt;br /&gt;
* &amp;amp;&amp;amp;  --&amp;gt; AND&lt;br /&gt;
* ||  --&amp;gt; OR&lt;br /&gt;
* !   --&amp;gt; NOT&lt;br /&gt;
&lt;br /&gt;
= Verilog für Simulation/Verifikation =&lt;br /&gt;
&lt;br /&gt;
Hier werden Sprachkonstrukte beschrieben die nicht synthesierbar sind und nur für die Verifikation im Zusammenhang mit einem Simulator sinnvoll sind.&lt;br /&gt;
&lt;br /&gt;
== System Tasks und Functions ==&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions sind ein Weg einen Verilog Simulator mit Funktionen zu erweitern. In diesem Abschnitt werden einige gängige System Tasks beschrieben die im Verilog Standard spezifiziert sind und somit in allen bekannten Simulatoren implementiert sind.&lt;br /&gt;
&lt;br /&gt;
System Tasks und Functions beginnen immer mit einem Dollarzeichen ($) und werden in der Regel von Synthesis-Tools ignoriert.&lt;br /&gt;
&lt;br /&gt;
=== $display ===&lt;br /&gt;
&lt;br /&gt;
Der $display Task wird verwendet um Informationen zum stdout zu schreiben. Die Form der Benutzung ist sehr an die printf() Funktion von C angelehnt. Ein wesentlicher Unterschied ist, dass mit der $display Funktion automatisch ein Zeilenvorschub angehängt wird und so kein extra &amp;quot;\n&amp;quot; am Ende des Strings gesetzt werden muss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt; &lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  i = 10;&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn der Task ausgeführt wird, ersetzt der Simulator %d mit dem Wert von i. Die Darstellung kann unterschiedlich formatiert werden und es gibt folgende Formatierungsbefehle:&lt;br /&gt;
&lt;br /&gt;
*%d - dezimal&lt;br /&gt;
*%h - hexadezimal&lt;br /&gt;
*%b - binär&lt;br /&gt;
*%o - oktal&lt;br /&gt;
*%s - string&lt;br /&gt;
*%c - ASCII Zeichen&lt;br /&gt;
*%v - Signalstärke&lt;br /&gt;
*%m - Hierarchischer Name&lt;br /&gt;
&lt;br /&gt;
Einen zusätzlichen Zeilenvorschub erhält man durch \n, Tab z.B. durch \t.&lt;br /&gt;
&lt;br /&gt;
Ein weitere Unterschied zu printf ist, dass mit $display die Zahlen rechtsbündig ausgerichtet werden. In manchen Fälle mag das nicht erwünscht sein und so besteht die Möglichkeit den Formatierungsbefehl %d z.B. in der Form %0d zu schreiben. Jetzt wird die Zahl linksbündig ausgerichtet.&lt;br /&gt;
&lt;br /&gt;
Am Beispiel eines integer Datentyp sei das verdeutlicht:&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
  integer i;&lt;br /&gt;
  ...&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %d&amp;quot;, i);&lt;br /&gt;
  $display(&amp;quot;Hallo Welt Nr. %0d&amp;quot;, i);&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im ersten Fall werden so viele Leerzeichen nach dem Wort &#039;Nr.&#039; eingefügt, damit die Zahl rechtsbündig dargestellt wird. Mit der %0d Version wird die Zahl linksbündig dargestellt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
Hallo Welt Nr.          10&lt;br /&gt;
Hallo Welt Nr. 10&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die linksbündige Darstellung wird von den Formatierungsbefehlen %d, %o, und %h unterstützt.&lt;br /&gt;
&lt;br /&gt;
=== $monitor ===&lt;br /&gt;
&lt;br /&gt;
Ähnlich dem $display Task schreibt der $monitor Task den Text zum stdout. Einziger Unterschied ist, dass der Task automatisch überprüft ob eines der Signal sich geändert hat und jedes mal bei einer Änderung einen neuen Ausdruck durchführt.&lt;br /&gt;
&lt;br /&gt;
=== $finish ===&lt;br /&gt;
&lt;br /&gt;
Beendet die Simulation. Jede Testbench sollte einen $finish System Task haben um die Simulation zu beenden.&lt;br /&gt;
&lt;br /&gt;
= Synthesierbare Konstrukte =&lt;br /&gt;
&lt;br /&gt;
== Kombinatorische Logik ==&lt;br /&gt;
&lt;br /&gt;
Das folgende Beispiel zeigt einen 2:1 Multiplexer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Mein2zu1Mux ( input [3:0] d0, d1,&lt;br /&gt;
                     input       sel,&lt;br /&gt;
                     output      y);&lt;br /&gt;
&lt;br /&gt;
  assign y = sel ? d1 : d0;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein neuer Operator der hier vorgestellt wird ist der Entscheidungsoperator (?:), im Englischen als conditional operator bezeichnet. Für bedingte Zuweisungen kann er an Stelle von der &#039;&#039;if&#039;&#039; oder &#039;&#039;case&#039;&#039; Anweisung verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Dem Signal y wird in Abhängigkeit von seö entweder d1 oder d0 zugewiesen. Ist sel wahr wird d1 zugewiesen, ist es falsch wird d0 zugewiesen.&lt;br /&gt;
&lt;br /&gt;
Natürlich kann der Operator auch verschachtelt werden, irgendwann macht das aber keine Sinn mehr und wird unübersichtlich. Der Entscheidungsoperator kann dann durch ein &#039;&#039;case&#039;&#039; Anweisung ersetzt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module mux ( input sel,&lt;br /&gt;
             input d0,&lt;br /&gt;
             input d1,&lt;br /&gt;
             input d2,&lt;br /&gt;
             input d3,&lt;br /&gt;
             output y);&lt;br /&gt;
  &lt;br /&gt;
  always @(*)&lt;br /&gt;
    case (sel)&lt;br /&gt;
      2&#039;b00: y = d0;&lt;br /&gt;
      2&#039;b01: y = d1;&lt;br /&gt;
      2&#039;b10: y = d2;&lt;br /&gt;
      2&#039;b11: y = d3;&lt;br /&gt;
    endcase&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Getreu der Empfehlung für die Zuweisung kombinatorischer Logik wurde hier die blockierende Zuweisung verwendet.&lt;br /&gt;
&lt;br /&gt;
In Bezug auf die Synthese ist zu beachten, dass alle Kombinationen von sel in der case-Anweisung enthalten sein müssen, sonst ist es möglich das durch die Synthese ein Latch entsteht. Näheres kann dazu im Synthesis User&#039;s Guide des jeweiligen FPGA Herstellers gefunden werden.&lt;br /&gt;
&lt;br /&gt;
== Sequentielle Logik ==&lt;br /&gt;
&lt;br /&gt;
Analog zum VHDL &#039;&#039;process&#039;&#039; wird in Verilog die &#039;&#039;always&#039;&#039; Anweisung verwendet. Ein einfaches Register synchron zur steigenden Flanke des Taktsignals wird wie folgt beschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;verilog&amp;gt;&lt;br /&gt;
module Flop (input            clk,&lt;br /&gt;
             input [3:0]      d,&lt;br /&gt;
             output reg [3:0] q);&lt;br /&gt;
&lt;br /&gt;
  always @ (posedge clk)&lt;br /&gt;
    q &amp;lt;= d;&lt;br /&gt;
&lt;br /&gt;
endmodule&lt;br /&gt;
&amp;lt;/verilog&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analog zur steigenden flanke kann auch auf die fallende Flanke mit &#039;&#039;negedge&#039;&#039; getriggert werden.&lt;br /&gt;
&lt;br /&gt;
= Open-Source Simulatoren =&lt;br /&gt;
&lt;br /&gt;
*http://icarus.com&lt;br /&gt;
*http://www.pragmatic-c.com/gpl-cver/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Referenz =&lt;br /&gt;
&lt;br /&gt;
== Bücher ==&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;The Verilog Hardware Description Language&amp;quot;, Thomas &amp;amp; Moorby, Kluwer Academic Publisher&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
*[http://www.asic-world.com/verilog/index.html ASIC World Verilog Tutorial]&lt;br /&gt;
*[http://www.sunburst-design.com Cliff Cummings Verilog &amp;amp; System Verilog Seite]&lt;br /&gt;
**[http://www.sunburst-design.com/papers/ Veröffentlichungen von Cliff Cummings]&lt;br /&gt;
&lt;br /&gt;
*[http://www.sutherland-hdl.com/ Sutherland HDL]&lt;br /&gt;
** [http://sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf Verilog 2001 Referenz als PDF]&lt;br /&gt;
** [http://www.sutherland-hdl.com/papers-by-sutherland.php Veröffentlichungen von Stuart Sutherland]&lt;br /&gt;
&lt;br /&gt;
[[Category:FPGA und Co]]&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=Diskussion:Verilog&amp;diff=28297</id>
		<title>Diskussion:Verilog</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=Diskussion:Verilog&amp;diff=28297"/>
		<updated>2008-05-30T14:35:45Z</updated>

		<summary type="html">&lt;p&gt;Guenter: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;bei mir stellt sich die frage: was ist eigentlich die favorisierte hdl sprache? verilog oder vhdl? verilog sieht für mich (c progger) wesentlich besser erlernbar aus als vhdl (k.a. pascal / ada(??)syntax)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
In erster Linie ist favorisiert was du einfacher lernen kannst und wenn du es professionell machst, was der Chef oder Kunde sagt. Oft höre ich immer wieder das in Nord Amerika und Asien Verilog bevorzugt wird und in Europa mehr VHDL. Das mit Europa stimmt aber so generell auch nicht. Hier würde ich noch die Unterscheidung zwischen FPGA- und ASIC- bzw. IC-Entwicklung machen. Bei letzteren scheint mir auch in Europa mehr Verilog zum Einsatz zu kommen.&lt;br /&gt;
&lt;br /&gt;
Erlernen ist wieder eine andere Sache. Erlernbar sind wohl beide, aber VHDL hat schon einige Syntax-Quirks, an die man sich erst mal gewöhnen muss wenn man schon einige Programmiersprachen kennt. Und dann benötigen gleiche synthesierbare Konstrukte mit VHDL in der Regel mehr Code als mit Verilog.&lt;br /&gt;
&lt;br /&gt;
Das Problem mit dem Erlernen ist aber auch noch eine andere Sache. Nämlich wenn man mal nach Hilfe sucht und dann nur die Antwort bekommt: &amp;quot;Verilog kenne ich nicht&amp;quot;. Was natürlich teilweise auch wieder auf die pauschale Aussage zurück zu führen ist das &amp;quot;wir in Europa nur VHDL machen&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Das war auch eine Motivation für mich hier eine kleine Einführung in Verilog zu schreiben. &lt;br /&gt;
&lt;br /&gt;
Mich würden natürlich Rückmeldungen interessieren, wie gut verständlich der Artikel ist.&lt;br /&gt;
--[[Benutzer:Guenter|Guenter]] 22:37, 29. Mai 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
Die C-Ähnlichkeit von verilog ist ein Nachteil für den Einstieg in die FPGA-Technik, kein Vorteil. Es wird keine CPU programmiert, sondern Hardware beschrieben. schreibt man den FPGA-Code wie man C programmiert kommt man ziemlich zackig zu Code der nicht synthetisierbar ist (in einen FPGA passT) oder sehr schlecht ist. (Hatte mal einen FPGa-Code von einem Programmierer, &lt;br /&gt;
elegant programmiert mit rekursiven Aufrufen und so, passte auch nach viel Gewürge in einen FPGA, lief aber nicht mit Taktraten größer 800 kHz. Tja ..&lt;br /&gt;
&lt;br /&gt;
Das Problem gibt es mit VHDL genauso häufig, siehe Forum. --[[Benutzer:Andreas|andreas]] 16:27, 30. Mai 2008 (CEST)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
Du verwechselst hier Syntax mit Methodik. Nur weil Verilog einen C-ähnlichen Syntax hat ist das keine Nachteil um in die Hardwarebeschreibung einzusteigen. Wenn ein Nutzer jedoch mit der Methodik von Softwareentwicklung an die Hardwarebeschreibung geht, dann ist das ein Problem. Das gleiche würde mit VHDL genauso passieren. Aber das sollte nicht hier sondern wenn Bedarf besteht im Forum diskutiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Platz hier ist sinnvoller für Diskussion über das eigentliche Dokument.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Guenter|Guenter]] 16:35, 30. Mai 2008 (CEST)&lt;/div&gt;</summary>
		<author><name>Guenter</name></author>
	</entry>
</feed>