Einführung in VHDL und Anleitung zur CPLD Simulation und Synthese
Transcription
Einführung in VHDL und Anleitung zur CPLD Simulation und Synthese
Einführung in VHDL und Anleitung zur CPLD Simulation und Synthese Z ÜRCHER H OCHSCHULE FÜR A NGEWANDTE W ISSENSCHAFTEN I NSTITUTE OF E MBEDDED S YSTEMS Autoren: Letzte Änderung: Hans-Joachim Gelke 24. Februar 2009 Inhaltsverzeichnis Inhaltsverzeichnis Abbildungsverzeichnis iii Tabellenverzeichnis iv Listings v 1 1 Die Hardwarebeschreibungssprache VHDL 1.1 1.2 1.3 1.4 1.5 1.6 2 Was ist eine Hardwarebeschreibung? . . . . . . . . . . . . . . . Was ist VHDL? . . . . . . . . . . . . . . . . . . . . . . . . . . Aufbau einer VHDL-Schaltungsbeschreibung . . . . . . . . . . 1.3.1 Schnittstellenbeschreibung (Entity) . . . . . . . . . . . 1.3.2 Die Funktionsbeschreibung (Architecture) . . . . . . . . 1.3.3 Erzeugung einer Hierarchie durch Strukturbeschreibung 1.3.3.1 Beispiel einer Strukturbeschreibung . . . . . . Grundelemente von VHDL . . . . . . . . . . . . . . . . . . . . 1.4.1 Identifier . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.2 Kommentare . . . . . . . . . . . . . . . . . . . . . . . 1.4.3 Daten-Objekte . . . . . . . . . . . . . . . . . . . . . . 1.4.4 Daten-Typen . . . . . . . . . . . . . . . . . . . . . . . 1.4.5 Operatoren . . . . . . . . . . . . . . . . . . . . . . . . Verhaltensbeschreibung in VHDL . . . . . . . . . . . . . . . . 1.5.1 Nebenläufige (Concurrent) Anweisungen . . . . . . . . 1.5.1.1 „WHEN_ELSE“-Anweisung . . . . . . . . . 1.5.1.2 „SELECT_WHEN“-Anweisung . . . . . . . 1.5.2 Sequenzielle (Sequential) Statements und Prozesse . . . 1.5.2.1 „IF_ELSIF“ im Prozess . . . . . . . . . . . . 1.5.2.2 Die „CASE_WHEN„Anweisung im Prozess . 1.5.2.3 Erzeugen von getakteten Flip-Flops . . . . . . 1.5.2.4 Zähler in VHDL . . . . . . . . . . . . . . . . 1.5.2.5 Konvertierungsroutinen . . . . . . . . . . . . 1.5.2.6 Zustandsautomaten . . . . . . . . . . . . . . VHDL Kode zum Verifizieren von Schaltungen . . . . . . . . . 1.6.1 Architecture der Testbench . . . . . . . . . . . . . . . . 1.6.2 Erzeugung von Takten . . . . . . . . . . . . . . . . . . 1.6.3 Assert Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CPLD Design Flow 2.1 2.2 1 2 3 4 5 6 6 9 9 9 9 10 11 12 12 13 13 13 15 16 16 17 18 19 22 22 22 23 24 Einrichten von Lizenzen auf Windows XP . . . . . . . . . . . . . . . . . . . . . . . Arbeiten mit dem Mentor ModelSim Simulator . . . . . . . . . . . . . . . . . . . . 2.2.1 Anlegen einer Verzeichnissstruktur . . . . . . . . . . . . . . . . . . . . . . 2.2.2 Vorbereiten eines „compile.do“ files für VHDL simualtion (vor der Synthese) 2.2.3 Aufsetzen eines ModelSim Projektes . . . . . . . . . . . . . . . . . . . . . 2.2.4 Generieren eines wave.do files . . . . . . . . . . . . . . . . . . . . . . . . . i . . . . . . . . . . . . 24 25 25 27 27 30 Inhaltsverzeichnis 2.3 2.2.5 Simulationswarnungen . . . . . . . . . . . . . . . . . . . 2.2.6 Backannotierte Simulation . . . . . . . . . . . . . . . . . Aufsetzen einer CPLD Synthese mit Altera Quartus . . . . . . . . 2.3.1 Aufsetzen eines Quartus Projektes . . . . . . . . . . . . . 2.3.2 Hinzufügen oder Entfernen von Dateien aus einem Projekt 2.3.3 Starten der Synthese . . . . . . . . . . . . . . . . . . . . 2.3.4 Auswerten der Berichte nach Synthese Place und Route . 2.3.5 Zuweisen von I/O Pins . . . . . . . . . . . . . . . . . . . Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 31 33 33 35 35 36 36 37 ii Abbildungsverzeichnis 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 Schaltplan eines RS-Flip-Flop . . . . . . . Syntax der Entity . . . . . . . . . . . . . . Syntax der Architecture . . . . . . . . . . . Struktur des Volladdierers . . . . . . . . . . Nebenläufige und Sequentielle Ausführung Zustände eines Zählers mit 6 Schritten . . . Die zwei Prozesse des Zählers . . . . . . . Blockdiagram eines Mealy Automaten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 5 6 7 14 17 17 20 2.1 2.2 2.3 2.4 2.5 2.6 2.7 Typische Unterverzeichnisse in einem Projekt . . . . . . . Festlegen des Arbeitsverzeichnisses in dem Modelsim läuft Festlegen des Arbeitsverzeichnisses in dem Modelsim läuft Generieren der Delay Werte für Backannotierte Simulation Einstellen des Arbeitsverzeichnises . . . . . . . . . . . . . Wählen des CPLDs . . . . . . . . . . . . . . . . . . . . . Wählen des Mentor Graphics EDA tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 28 29 32 33 34 35 iii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tabellenverzeichnis Tabellenverzeichnis 1.1 Mit numeric_std zur Verfügung stehende Convertierungsroutinen . . . . . . . . . . . . . iv 19 Listings 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.18 1.19 1.20 1.21 1.22 1.23 1.24 1.25 1.26 1.27 1.28 1.29 1.30 1.31 1.32 1.33 Anschlüsse eines RS-FF . . . . . . . . . . . . . . . . . . . . Entity RS-FF mit std_logic . . . . . . . . . . . . . . . . . . . Funktionsbeschreibung des RS-FF . . . . . . . . . . . . . . . Struktur des Volladierers . . . . . . . . . . . . . . . . . . . . Beispiel für Named Association . . . . . . . . . . . . . . . . Kommandozeile . . . . . . . . . . . . . . . . . . . . . . . . . Daten Objekte . . . . . . . . . . . . . . . . . . . . . . . . . . Beispiele von Deklarationen . . . . . . . . . . . . . . . . . . Deklaration von Vektoren . . . . . . . . . . . . . . . . . . . . Zuweisung von Werten . . . . . . . . . . . . . . . . . . . . . Deklarierung von eigenen Datentypen . . . . . . . . . . . . . Datentypen zum Beschreiben von Automaten . . . . . . . . . Verwendung von Operatoren . . . . . . . . . . . . . . . . . . Verknüpfung von Strings . . . . . . . . . . . . . . . . . . . . Nebenläufige Anweisungen . . . . . . . . . . . . . . . . . . . Multiplexer mit logischen Gleichungen ausgedrückt . . . . . . Multiplexer mit WHEN-ELSE ausgedrückt . . . . . . . . . . Multiplexer mit SELECT_WHEN ausgedrückt . . . . . . . . Sensitivity Liste . . . . . . . . . . . . . . . . . . . . . . . . . D-FF mit asynchronem Reset . . . . . . . . . . . . . . . . . . Multiplexer mit IF_ELSIF ausgedrückt . . . . . . . . . . . . . Multiplexer mit CASE Statement ausgedrückt . . . . . . . . . Erzeugen eines D-FF . . . . . . . . . . . . . . . . . . . . . . DFF mit asynchronem Reset . . . . . . . . . . . . . . . . . . Code Beispiel eines Zählers . . . . . . . . . . . . . . . . . . . Umwandlung von Integer in std_logic_vector . . . . . . . . . Umwandlung von std_logic_vector in Integer . . . . . . . . . Beispiel eines Mealy Automaten . . . . . . . . . . . . . . . . ENtity einer Testbench . . . . . . . . . . . . . . . . . . . . . Erzeugen eines Taktes . . . . . . . . . . . . . . . . . . . . . . Melden von Simulationsfehlern . . . . . . . . . . . . . . . . . Prüfen des Signals sig_reset . . . . . . . . . . . . . . . . . . Unterdrückung der Fehlermeldung am Anfang der Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 5 7 8 9 9 9 10 10 11 11 11 11 12 12 13 13 14 15 15 16 16 16 18 18 18 20 22 22 23 23 23 2.1 2.2 2.3 Das compile.do script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Compilierung ist richtig, aber es fehlt noch das wave.do . . . . . . . . . . . . . . . . . . Script für Simulation mit Backannotation . . . . . . . . . . . . . . . . . . . . . . . . . 27 29 32 v . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Die Hardwarebeschreibungssprache VHDL Dieses Kapitel soll einen ersten Eindruck von der Hardwarebeschreibungssprache VHDL vermitteln. Für einen tiefen, gründlichen Einstieg in VHDL sind ist die vorgeschlagene Literatur empfohlen: • „An Introductory VHDL Tutorial“ von der Firma Green Mountain Computing Systems; im HTMLFormat: /eda/g m- vhd1/ 1ib/tutoria1.htm • „VHDL Kurzbeschreibung“ von Andreas Mäder, Universität Hamburg; 120 Seiten im PDF-Format: /www/vhdl/maeder/vhdl .pdf • „How to declare in VHDL“ von der Firma MINC Inc.; 113 Seiten im PDF Format: /eda/minc_int/pls_doc/how_vhdl.pdf Die im Anhang zu diesem Kapitel genannten Bücher bieten eine weitere Möglichkeit, um sich genauere Kenntnisse über VHDL anzueignen. Unter den deutschsprachigen Büchern bietet [GL94] eine umfassende und gut verständliche Einführung, während bei den angloamerikanischen Titeln [Pel96] als sehr praxisnahes Buch hervorzuheben ist. Als weiterer Schritt kann der Einsatz eines Lernprogramms oder die Teilnahme an einer VHDL-Schulung in Erwägung gezogen werden. Die Übungen im MeK1 Labor sollten aber für die meisten VHDL Anwendungen ausreichend sein. 1.1 Was ist eine Hardwarebeschreibung? Anhand der Sprache VHDL wird in diesem Kapitel dargestellt, wie eine Hardwarebeschreibungssprache (HDL) aussieht, wie sie aufgebaut ist und welche Vor- und Nachteile die Anwendung einer HDL bietet. Vieles, was in diesem Kapitel allgemein zu VHDL gesagt wird, gilt natürlich entsprechend für andere HDLs. VHDL ist nur eine HDL unter vielen. In der Vergangenheit haben Halbleiterhersteller und Hersteller von EDA-Werkzeugen ihre eigenen Sprachen entwickelt, wie z.B. PALASM, ABEL, CUPL, ALTERA-HDL. Diese Sprachen haben zumeist einen einfachen Aufbau und sind für den Entwurf von PLDs gedacht. In den letzten 10 Jahren haben sich aber auch in diesem Bereich VHDL und Verilog als Standard durchgesetzt. Fast genauso Verbreitet wie VHDL ist die Sprache Verilog. Diese wurde von der Firma Gateway Design Automation eingeführt und hat sich durch die Firma Cadence vor allem im Bereich des ASIC-Entwurfs einen Platz erobert. Während Verilog eher an die Programmiersprache C angelehnt ist, erinnert VHDL mehr an PASCAL oder ADA. Verilog wurde 1995 als IEEE 1364 genormt und ist vor allem in den USA weit verbreitet. VHDL ist eine universelle Programmiersprache, die für den Entwurf von digitalen Schaltungen optimiert ist. Daher kann VHDL benutzt werden zur: • Spezifikation • Entwurfseingabe • Simulation • Synthese 1 1 Die Hardwarebeschreibungssprache VHDL • Dokumentation und Archivierung von Schaltungen Da VHDL auch die Beschreibung einer Schaltung auf einer hohen Abstraktionsebene erlaubt, kann VHDL bereits bei der Spezifikation eines Entwurfs eingesetzt werden. Die dabei erstellten Festlegungen, wie die Aufteilung in einzelne Blöcke und die Definition der Schnittstellen, können bei der weiteren Schaltungseingabe benutzt werden. Bei der Entwurfseingabe ist VHDL im Vergleich zur Schaltplaneingabe zu betrachten. Ein VHDL-Modell hat hier den Vorteil, dass es parametrisierbar und unabhängig von der Zieltechnologie ist. Ausserdem lassen sich regelmässige Strukturen sehr leicht erzeugen. VHDL-Modelle können auf allen Abstraktionsebenen simuliert werden. Damit können Fehler sehr frühzeitig entdeckt werden. Von Vorteil ist dabei, dass eine einmal erstellte Simulationsumgebung (engl.: Testbench) auf allen Ebenen benutzt werden kann. Durch die Synthese werden die Abstraktionsebenen automatisch überbrückt und so der Entwurfsablauf - besonders bei grossen Schaltungen - wesentlich beschleunigt. Diese durchgängige Verwendung von VHDL bis hin zur Dokumentation ist auch gleichzeitig einer der grössten Vorteile beim Einsatz von VHDL. Der Datenaustausch zwischen den verschiedenen Entwurfsebenen, zwischen den verschiedenen Entwurfswerkzeugen, zwischen den verschiedenen Entwicklern eines Projektteams und auch zwischen Auftraggeber und Auftragnehmer eines Projektes ist damit einfach möglich. Dies war auch ein Hauptanliegen, als Anfang der 80er Jahre die Sprache VHDL entwickelt wurde. Beim Einsatz von VHDL sind einige Punkte zu beachten. Auch ergeben sich einige Nachteile, die nicht verschwiegen werden sollen. VHDL ist eine Programmiersprache. Von daher hat das Erstellen eines VHDL-Modells viel gemein mit dem Erstellen eines Programms. Der Ablauf, die Denkweise und die Werkzeuge entsprechen dem vertrauten Umfeld eines Software-Entwicklers, nicht jedoch dem eines Hardware-Entwicklers. Für den (reinen) Hardware-Entwickler ist daher ein Umdenken und das Erlernen neuer Techniken erforderlich. Dies ist mit Sicherheit das grösste Hindernis bei der Einführung von VHDL. Die alte Weisheit „Eine Stunde Programmieren erspart eine Minute Denken“ gilt auch beim Erstellen von VHDL-Modellen. Die schöpferische Fähigkeit, die Intuition und die Erfahrung des Hardware-Entwicklers kann - zumindest noch - nicht durch EDA-Werkzeuge ersetzt werden. Um VHDL produktiv einsetzen zu können, muss der Entwickler nicht nur die Sprache kennen, sondern auch wissen, wie sie gewinnbringend eingesetzt werden kann. 1.2 Was ist VHDL? Die Hardwarebeschreibungssprache VHDL wurde im Auftrag der US-Regierung im Rahmen des VHSICProjekts entwickelt. VHDL steht für V VHSIC = Very High Speed Integrated Circuit HDL Hardware Description Language Mit VHDL kann eine Schaltung auf unterschiedliche Weise dargestellt werden. VHDL stellt Sprachelemente zur Verfügung, die sowohl eine Beschreibung des Verhaltens als auch der Struktur einer Schaltung erlauben. Neben diesen beiden grundlegenden Sichten kann auch der Datenfluss beschrieben und das zeitliche Verhalten dargestellt werden. VHDL ist eine grosse, komplizierte und mächtige Sprache. Spötter deuten daher VHDL als „Very Hard to Deal with Language“. Dies mag der Fall sein, will -oder muss - man wirklich in die tiefsten Details von VHDL eintauchen, z.B. um Simulationsmodelle oder Synthesealgorithmen zu erstellen. Es ist jedoch nicht notwendig, alle Einzelheiten von VHDL zu kennen, bevor man mit den ersten Entwürfen starten kann. Viele der fortgeschrittenen Möglichkeiten werden zu Beginn nicht benötigt und können nach und nach „erkundet“ werden. Es ist ratsam, sich zunächst an bewährte Konventionen bei der Erstellung eines VHDL-Modells zu halten und sich freizügig Anleihen 2 1.3 Aufbau einer VHDL-Schaltungsbeschreibung bei existierenden Beispielen zu holen. Das Kopieren aus vorhandenen VHDL Modellen erleichtert zudem die mühsame Eingabe der Modelle, die schon für einfache Schaltungen recht umfangreich werden können. Die Sprache VHDL wurde 1987 als IEEE 1076 standardisiert. Eine überarbeitete Version wurde 1994 als IEEE 1076-1993 freigegeben. Um eine einheitliche Simulation von VHDL-Modellen auf verschiedenen Simulatoren zu gewährleisten, wurde mit dem Standard IEEE 1164 das Package std_logic_1164 definiert. Ein Package ist ein VHDL-Entwurfselement, das eine Sammlung von Deklarationen beinhaltet. Das Package std_logic_1164 beinhaltet das 9-wertige Logiksystem std_ulogic zur genaueren Modellierung verschiedener Signalstärken sowie davon abgeleitete Logiksysteme, die zugehörigen logischen Operatoren und Konvertierungsfunktionen. Zur Beschleunigung der Simulation von VHDL-Modellen auf der Gatterebene hat die VITAL-Initiative (VHDL Initiative Toward ASIC Libraries) den Standard IEEE 1076.4 entwickelt. Es wurden zum einen genormte Modelle auf Gatterebene definiert und zum anderen eine Methode zum Annotieren von TimingInformationen. Dabei wurden bewährte Konzepte der Sprache Verilog übernommen. Eine Erweiterung von VHDL für analoge Schaltungen ist AHDL. Diese analoge HDL (AHDL) ist als IEEE 1076.1-1999 genormt worden. 1.3 Aufbau einer VHDL-Schaltungsbeschreibung Ein VHDL-Modell besteht aus einzelnen Entwurfseinheiten. Eine Entwurfseinheit ist ein abgeschlossener Block von Anweisungen, die einzeln überprüft und simuliert werden kann. Die Beschreibung einer Entwurfseinheit besteht in VHDL aus drei Teilen: 1. Die Schnittstellenbeschreibung genannt Entity 2. Die Funktionsbeschreibung genannt Architecture 3. Zuordnungsbeschreibung genannt Configuration Eine Configuration ist nur dann erforderlich, wenn mehr als eine Architektur zur Auswahl steht. Im folgenden soll die VHDL Beschreibung eines RS-Flip-Flop beschrieben werden. Die Entsprechende Architecture Gatter Schaltung ist hier aufgezeigt. Beisp: RS - Flip Flop mit NOR Gates R ARCHITECTURE comb OF rsff IS >1 Q >1 Qn BEGIN q <= not (r or qn); qn <= not (s or q); END comb; S Abbildung 1.1: Schaltplan eines RS-Flip-Flop 3 1 Die Hardwarebeschreibungssprache VHDL 1.3.1 Schnittstellenbeschreibung (Entity) Für die Entity wird das zu beschreibende System als „Black Box“ betrachtet. In der Schnittstellenbeschreibung werden nur die nach aussen führenden Signale mit ihren Bezeichnungen, Modi und Typen aufgeführt. ENTITY rsff IS PORT ( s,r : IN bit; q,qn: OUT bit); END rsff; Listing 1.1: Anschlüsse eines RS-FF Es wurde dabei für alle vier Ports der vordefinierte Typ b i t benutzt. Dieser Typ kann die Werte ’0’ und ’1’ annehmen. Wenn das oben erwähnte Package std_logic_1164 in ein VHDL-Modell mit eingebunden wird, dann kann z.B. auch der darin definierte Typ std_logic benutzt werden. Dieser Typ kennt folgende Werte: • Starke Signalwerte: ’0’,’1’, ’ X’ • Schwache Signalwerte: ’ L’, ’H’, ’W’ • Hochohmige Tristate-Ausgänge: ’ Z’ • Nichtinitialisierte Signale: ’U’ • Don’t Care: ’-’ Die Signalwerte ’X’ und ’W’ stellen dabei den Zustand „unbekannt“ dar. Die Entity-Beschreibung würde dann wie folgt aussehen: library ieee; use ieee.std_logic_1164.a11 ENTITY rsff IS PORT ( s,r : IN std_logic; datain : IN std_logic; q,qn: OUT std_logic; c d ) : std_logic_vector(7 downto 0); : std_logic_vector(7 downto 0) END rsff; Listing 1.2: Entity RS-FF mit std_logic Dabei dienen die ersten beiden Zeilen zur Einbindung und Bekanntmachung der Deklarationen in dem Package std_logi c_1164. 4 Entity (Beschreibung der Ein-Ausgänge eines Funktionsblocks) 1.3 Aufbau einer VHDL-Schaltungsbeschreibung Reservierte Worte: Dürfen nicht als frei wählbare Namen verwendet werden Mode: IN¦OUT¦INOUT ENTITY rsff IS PORT ( s,r : IN std_logic; Name der Entity, frei wählbar q,qn: OUT std_logic); END rsff; Type: std_logic_vector¦std_logic¦unsigned Abbildung 1.2: Syntax der Entity 1.3.2 Die Funktionsbeschreibung (Architecture) Der zweite Teil einer Entwurfseinheit ist die sogenannte Architecture. Diese gibt die Funktion der Entwurfseinheit an, indem das Verhalten und/ oder die Struktur beschrieben wird. Als Beispiel soll hier zunächst eine Architecture angegeben werden, die das Verhalten der Entwurfseinheit RSFF beschreibt: ARCHITECTURE comb OF rsff IS BEGIN q <= not (r or qn); qn <= not (s or q); c(7) <= datain; --assigning a signal to a single bit of a vector c(6 downto 0) <= c(7 downto 1); d <= (others => ’0’); --set all bits of vector d to zero END comb; Listing 1.3: Funktionsbeschreibung des RS-FF Enthält ein VHDL-Modell, wie in diesem Fall, nur eine Architecture der Entwurfseinheit RSFF, so ist mit den beiden Objekten Entity und Architecture die Beschreibung vollständig. Die beiden hier benutzten Operatoren or und not gehören zu den in VHDL vordefinierten Operatoren. Sind die beiden Operanden A und B vom Typ bit, so ist das Ergebnis ebenfalls von diesem Typ. Wird jedoch wie in de zweiten Entity das Package std_logic_1164 eingebunden, so werden durch das sogenannte Operator-Overloading die Operatoren so erweitert, dass sie z.B. auch Signale des Typs std_logic verarbeiten können. Das Ergebnis einer solchen Operation ist dann auch vom Typ std_logic. 5 Architecture 1 (Beschreibung Die Hardwarebeschreibungssprache VHDL des Verhaltens eines Blockes) Frei wählbarer Name der Architektur Name der Entity zu der die Architektur gehört ARCHITECTURE comb OF rsff IS BEGIN q <= not (r or qn); qn <= not (s or q); END comb; Inhalt der Architektur Abbildung 1.3: Syntax der Architecture Zu jeder Entity gehört immer eine Architektur. Architektur und Entity treten immer als Paar auf. VHDL unterscheidet zwei grundsätzliche Methoden der Schaltungsbeschreibung: die Verhaltensbeschreibung (Behavioral Description) und die Strukturbeschreibung (Structural Description). Bei der Verhaltensbeschreibung wird das Verhalten der Schaltung durch Boolesche Gleichungen oder durch Prozesse (z.B. für Zustands-Maschinen) beschrieben. Die Strukturbeschreibung geht davon aus, jedes System durch Zusammenschalten von bereits definierten Blöcken (Komponenten) zu realisieren. Der Name der Architektur ist frei wählbar, jedoch haben sich Konventionen Eingebürgert. Beschreibt die Architektur Struktur, so nennt sie sich struct. Beschreibt sie kombinatorische Logik, so nennt sie sich comb. Beschreibt sie Register, nennt sie sich reg. Das folgende Kapitel beschäftigt sich mit Strukturbeschreibung. 1.3.3 Erzeugung einer Hierarchie durch Strukturbeschreibung VHDL ermöglicht es komplexe Designs strukturiert aufzubauen. Ein Design kann dazu, zu Zwecken der Übersichtlichkeit und Arbeitsteilung, in kleinere Blöcke aufgeteilt werden. Diese Blöcke wiederum können aus Unterblöcken usw. bestehen. 1.3.3.1 Beispiel einer Strukturbeschreibung Mit zwei Halbaddierern und einem ODER-Gatter lässt sich entsprechend Abbildung 1.4 ein Volladdierer aufbauen. Dieser addiert die drei an seinen Eingängen anliegenden Bits A, B und C und bildet daraus den Summenausgang SUM und den Übertrag CRY. Das entsprechende VHDL-Modell ist als 1.3.3.1 abgedruckt. 6 5.4 1.3 Aufbau VHDLbeschreibt Struktur Mit zwei Halbaddierern und einem ODER-Gatter Iäßt sich entsprechend Abbildung 5.3 ein Volladdierer aufbauen. Dieser addiert die drei an seinen Eingängen anliegenden Bits A, B und C und bildet daraus den Summeneiner VHDL-Schaltungsbeschreibung ausgan€lSUM und den Übertrag CRY. Das entsprechendeVHDL-Modell ist als Listing 4 abgedruckt. VOLLADD Volladdierer .\rchite lahei u \etzlist -,,. . g l l \/^-- Y g l S L ' :' r r i r r i e r tD . .,- dek Dit' Kom jinitinnen -clrr'or Kornpo -(nen N t e s: o i " . a i r r a l eg e losition I r u n gd e A B a ,, x_ Abb. 5.3: Struktts LlesVolladdiercrs Abbildung 1.4: Struktur des Volladdierers e n t i t y V 0LL A D Di s L i s t i n g4 : port (A,B,C: in bjt; ENTITY volladd IS C R ,YS U [ 4 : o u t b i | ) ; PORT (A,B,C: IN std_logic; e n dV 0 L L A D D ; CRY,SUM: OUT std_logic); END volladd; 's a r c hi t e c t u r e S T R U K T oUfRV 0 L L A Dr D s i g n a lX 1 , X 2 , X 3b :r ' t ; ARCHITECTURE struct OF volladd c o m pISo n e nHt A L B A D D SIGNAL Xl,X2,X3: bit; 100 COMPONENT halbadd PORT (A,B: IN std_logic; CRY,SUM: OUT std_logic); END COMPONENT; COMPONENT odergat PORT (I1,I2: IN std_logic; OUT std_logic); OUTl: END COMPONENT; BEGIN ul: HALBADD port map( A => A, B => B, CRY => X1, sum => X2); u2: HALBADD port map( A => X2, B => C, CRY => X3, sum => SUM); u3: ODERGAT port map( OUT1 => CRY, I1 => Xl, I2 => X3); END struct; Listing 1.4: Struktur des Volladierers In Listing 1.3.3.1 wird zunächst die Entity des Volladdierers mit dem Namen V0LLADD und den Einund Ausgängen deklariert. Anschliessend folgt eine Architecture mit dem Namen struct zu dieser Entity. Es handelt sich dabei um eine reine Strukturbeschreibung. Dabei werden wie in einer Netzliste die verwendeten Signale und Komponenten aufgelistet und deren Verschaltung angegeben. 7 5.5 Eine Ve g n a l ea u angege VHDL-M ren Prnor 1 Die Hardwarebeschreibungssprache VHDL Zunächst werden nach dem Schlüsselwort SIGNAL die internen Signale mit ihrem jeweiligen Modus und Signaltyp definiert. Danach werden die benutzten Komponenten HALBADD und 0DER-GAT deklariert. Die Komponentendeklarationen sind ein Abbild der jeweiligen Entity-Definitionen. Der Name, der nach dem Wort Component steht, muss mit dem Namen der Entity übereinstimmen. Danach folgt die Deklarierung der Ports, welche man durch Copy-Paste direkt von der Entity übernehmen kann. Die eigentliche Strukturbeschreibung ist zwischen den Schlüsselworten BEGIN und END zu finden. Hier werden die zuvor deklarierten Komponenten instanziiert. Dabei erhalten die einzelnen Instanzen einen eigenen Namen. Analog zu ICs auf einer Leiterplatten kann man dazu U1, U2 usw. als Name wählen. Mit Hilfe des Schlüsselwortes PORTMAP werden die internen Signale (A,B,C,CRY,SUM) der Entity V0LLADD an die Signale( X1, X2, X3) angeschlossen. Die Zuordnung der Signale geschieht dabei durch eine Zuordnung der lokalen (OUTl, I1, I2 ) zu den aktuellen Signalnamen (CRY ,Xl,X3). Nach dem Doppelpunkt kommt der Name des Blockes. Innerhalb der Klammer von PORT MAP werden dann die Anschlüsse der Komponente (Linke Seite des Pfeils), mit den Signalen innerhalb des Blockes oder der Blockaussenanschlüsse verbunden (Rechte Seite des Pfeils). Dies Methode zum Anschliessen von Komponenten nennt man „Named Association“ und ist die Übersichtlichste. Es gibt aber noch eine Alternative Methode, die „Positional Assocation“, welche aber leicht zu Fehlern führt, da man die Reihenfolge der aufgeführten Signale genau einhalten muss. PORT MAP (rx_eingang, system_clk, tx_asugang, uart_int) Listing 1.5: Beispiel für Named Association Die einzelnen Design Dateien selbst stehen flach in einem Sourceverzeichnis. Actung: Dem Simulator oder Synthesizer muss man angeben, welche Entity-Architektur die höchste Hierarchiestufe hat. Beim compilieren analysiert der Simulator oder Synthesizer beginnend von der höchsten Hierarchiestufe anhand der Component Declaration wie die Hierarchie zusammengesetzt ist. 8 1.4 Grundelemente von VHDL 1.4 Grundelemente von VHDL 1.4.1 Identifier Ein gültiger Bezeichner in VHDL darf Gross- und Kleinbuchstaben (A ... Z, a ... z), Ziffern (0 ... 9) und den Unterstrich (_) enthalten. Er muss zwingend mit einem Buchstaben beginnen. Andere Zeichen sind nicht zulässig. Der Unterstrich darf nicht am Ende eines Bezeichners stehen; ebensowenig sind zwei aufeinanderfolgende Unterstriche erlaubt. In VHDL wird generell nicht zwischen Gross- und Kleinschreibung unterschieden; die Bezeichner SignalA, signala und SIGNALA bezeichnen alle dasselbe Signal. In VHDL existieren einige Schlüsselwörter, die, wie in anderen Programmiersprachen, nicht als Bezeichner verwendet werden dürfen (siehe Handbücher der VHDL-Compiler). 1.4.2 Kommentare Kommentare beginnen mit zwei aufeinanderfolgenden Bindestrichen (–) und umfassen den gesamten Rest der betreffenden Zeile. Kommentare können an jeder Stelle eines VHDL-Programmes auftreten. Beispiele: -- Das ist eine eigene Kommentarzeile -- auch eine zweite Zeile muss mit "‘--"’ eingeleitet werden ENTITY nand4 IS ( -- Kommentar bis zum Zeilenende Listing 1.6: Kommandozeile 1.4.3 Daten-Objekte Daten-Objekte gehören in VHDL zu einer von drei möglichen Objekt-Klassen: Konstanten, Variablen und Signale. Wie bei modernen Sprachen üblich, müssen Daten-Objekte auch in VHDL vor ihrer Verwendung deklariert werden. Das geschieht mit folgender Syntax: CONSTANT identifier [, identifier ...]: TYPE := value; VARIABLE identifier [, identifier ...]: TYPE [:= value]; SIGNAL identifier [, identifier ...]: TYPE [:= value]; Listing 1.7: Daten Objekte In eckige Klammern ([ ]) gesetzte Ausdrücke sind bei der Eingabe nicht zwingend erforderlich, können aber auftreten. Die Bedeutung von Konstanten, denen übrigens bei der Deklaration ein Wert zugewiesen werden muss, ist gleich wie in anderen Programmiersprachen. Die wichtigste Objektklasse sind sicher die Signale, die auch eine Hardware Entsprechung haben (Leitungen, Speicherbausteine). Die Variablen haben in VHDL eher die Bedeutung von Hilfsgrössen, aber sonst dieselben Eigenschaften wie Signale. CONSTANT bus width: INTEGER := 8; VARIABLE ctrl bits: std_logic_vector (7 DOWNTO 0); SIGNAL sig1, sig2, sig3: std_logic; Listing 1.8: Beispiele von Deklarationen 9 1 Die Hardwarebeschreibungssprache VHDL 1.4.4 Daten-Typen Die IEEE 1164 Library unterstützt unter anderem die folgenden vordefinierten VHDL-Datentypen: • integer • boolean • unsigned • signed • std_logic • std_logic_vector Eine Wertzuweisung könnte beispielsweise so aussehen: sigl <= ‘1’; Man beachte, dass der einem Objekt des Typs „bit“ oder „std_logic“ zugewiesene Wert in einfachen Anführungszeichen stehen muss! Ein „std_logic_vector“ ist ein „array of bit“ in aufsteigender oder absteigender Reihenfolge. Dieser Datentyp ist besonders bequem, um Bus-Signale zu beschreiben. SIGNAL SIGNAL SIGNAL a, c, e: std_logic_vector (0 TO 7); std_logic_vector (7 DOWNTO 0); std_logic_vector (0 TO 5); b: d: Listing 1.9: Deklaration von Vektoren Den eben deklarierten Signalen sollen nun Werte zugewiesen werden: a C b d e <= <= <= <= <= "00110101"; "00110101"; x"7A" x"7A" 0"25" Listing 1.10: Zuweisung von Werten Es wurden zwar hier den Signalen a und c die gleichen Werte zugewiesen (bei „std_logic_vector“ müssen die zugewiesenen Werte in doppelten Anführungsstrichen („“) stehen), aber wegen der abweichenden Reihenfolge der Indizierung enthalten die einzelnen Array-Elemente unterschiedliche Werte: a(7) = ’l’ a(6) = ’0’ a(5) = ’1’ a(4) = ’0’ a(3) = ’l’ a(2) = ’l’ a(1) = ’0’ a(0) = ’0’ c(7) = ’0’ c(6) = ’0’ c(5) = ’1’ c(4) = ’l’ c(3) = ’0’ c(2) = ’l’ c(l) = ’0’ c(0) = ’1’ Ein Präfix „X“ oder „x“ bedeutet, dass der Wert in hexadezimaler Form angegeben wird; „O“ oder „o“ bedeutet eine Angabe in oktaler Form. „B“ oder „b“ stehen schliesslich für binäre Darstellung, was auch automatisch angenommen wird, wenn kein Präfix verwendet wird. Die oktale bzw. die hexadezimale Form der Wertzuweisung ist nur anwendbar, wenn der „std_logic_vector“ eine passende Länge aufweist (Vielfaches von 3 bzw. von 4). Nebst den hier beschriebenen vordefinierten Datentypen existieren noch die selbstdefinierten Typen, unter denen der Aufzählungstyp eine besondere Bedeutung hat. Seine Deklaration lautet: 10 1.4 Grundelemente von VHDL TYPE name IS ( value [, value ...]); Listing 1.11: Deklarierung von eigenen Datentypen Beispiel: TYPE states IS (state0, statel, state2, state3); Listing 1.12: Datentypen zum Beschreiben von Automaten Es ist hier nicht notwendig, den Bezeichnern state0 etc. einen weiteren Typ zuzuweisen; eine Zuweisung erfolgt automatisch durch den Compiler. 1.4.5 Operatoren and or nand nor xor not Innerhalb der logischen Operatoren existiert keine Hierarchie; die Reihenfolge. in der die Operationen durchgeführt werden sollen, muss durch Klammern festgelegt werden. Beispiel: a <= (b and c) or d Listing 1.13: Verwendung von Operatoren Relationale Operatoren = < > gleich kleiner grösser /= <= >= ungleich kleiner gleich grösser gleich Addier-Operatoren + und - haben die gleiche Bedeutung wie in anderen Programmiersprachen, also Addition bzw. Subtraktion von Zahlen. & ist der Verknüpfungsoperator. Die Hauptanwendung ist die Verknüpfung von String-Konstanten. Dazu ein Beispiel: VARIABLE c: STRING; C:="0011001010" -- wird vor allem dann verwendet, &"11111" -- wenn ein String zu lang für eine & "010101"; -- Zeile ist Listing 1.14: Verknüpfung von Strings Zuweisungs-Operatoren := Zuweisung für Variablen: v:= 5; <= Zuweisung für Signale: s <_ (a AND b) XOR (c OR d) ; In VHDL werden für Signale und Variablen unterschiedliche Zuweisungsoperatoren verwendet. Assoziations-Operator Der Assoziations-Operator „=>“ stellt einen Zusammenhang zwischen verschiedenen Objekten her. Seine Anwendung kann fast nicht allgemein beschrieben werden, hingegen wird sie durch Beispiele klarer. 11 1 Die Hardwarebeschreibungssprache VHDL 1.5 Verhaltensbeschreibung in VHDL Eine Verhaltensbeschreibung in VHDL gibt an, wie sich die Ausgangssignale aufgrund der Zustände der Eingangssignale verhalten. Es wird nicht angegeben, wie dieses Verhalten realisiert wird. Der Aufbau eines solchen VHDL-Modells ähnelt auf den ersten Blick einem Programm in einer höheren Programmiersprache. Bei der Verhaltensbeschreibung unterscheidet man zwischen „gleichzeitigen“ Anweisungen (concurrent statements, nebenläufige Anweisungen) und sequentiellen Anweisungen innerhalb von Prozessen. Beide Anweisungstypen können innerhalb der gleichen Architekturdefinition gemischt vorkommen. 1.5.1 Nebenläufige (Concurrent) Anweisungen Concurrent-Anweisungen existieren ausserhalb von Prozessen und können fast beliebige Arten von Ausdrücken enthalten. Sie heissen „gleichzeitig“, weil sie alle zum gleichen Zeitpunkt ausgewertet werden; die Reihenfolge, in der die Anweisungen geschrieben werden, spielt also keine Rolle. Beispiele: u v w x y z <= <= <= <= <= <= a; u; a XOR b; (a AND s) OR (b AND NOT(s)); ‘1’ WHEN (a=’0’ AND b=’1’) ELSE ‘0’; a WHEN (count="0010") ELSE b; Listing 1.15: Nebenläufige Anweisungen Die Signale a, u und v haben alle den gleichen Wert, nämlich den von a. Dies wäre auch so, wenn die Reihenfolge der ersten beiden Zeilen umgestellt würde. Hier besteht die Möglichkeit, Denkfehler einzubauen, weil man sich von anderen Programmiersprachen her nicht an „gleichzeitige“ Anweisungen gewöhnt ist, sondern gedanklich alles sequentiell abarbeitet. Am Beispiel eines 4x4 Multiplexers sollen hier einige Möglichkeiten gezeigt werden, wie man ein und dasselbe Verhalten auf ganz verschiedene Arten beschreiben kann. Details zur Syntax müssen im jeweiligen Compiler-Handbuch nachgeschlagen werden. Im ersten Beispiel soll der Multiplexer mit logischen Gleichungen beschrieben werden: -- 4x4 Multiplexer mit logischen Gleichungen -- (concurrent statements) ENTITY mux IS PORT( a,b,c,d: IN std_logic_vector(3 DOWNTO 0); s: IN std_logic_vector(1 DOWNTO 0); x: OUT std_logic_vector(3 DOWNTO 0)); END mux; ARCHITECTURE archmux OF x(3) <= (a(3) AND OR (b(3) AND OR (c(3) AND OR (d(3) AND x(2) <= mux IS BEGIN NOT(s(1)) AND NOT(s(0))) NOT(s(1)) AND s(0)) s(1) AND NOT(s(0))) s(1) AND s(0)); ... END archmux; Listing 1.16: Multiplexer mit logischen Gleichungen ausgedrückt 12 1.5 Verhaltensbeschreibung in VHDL 1.5.1.1 „WHEN_ELSE“-Anweisung Die When_Else eine nebenläufige Anweisung und steht irgendwo zwischen begin und end Statement einer Architektur. Trifft eine Zeile zu, dann werden die nachfolgenden Zeilen nicht mehr abgefragt. Die oberen Abfragen haben demnach Priorität gegenüber den Abfragen die weiter unten vor kommen. Man kann somit eine Logik mit Priorität aufbauen. -- 4x4 Multiplexer mit "when-else" -- (concurrent statements) Anweisung ENTITY mux IS PORT( a,b,c,d: IN std_logic_vector(3 DOWNTO s: IN std_logic_vector(1 DOWNTO x: OUT std_logic_vector(3 DOWNTO END mux; ARCHITECTURE archmux OF mux x <= a WHEN (s="’00"’) b WHEN (s="’01"’) c WHEN (s="’10"’) 0); 0); 0)); IS BEGIN ELSE ELSE ELSE d; Listing 1.17: Multiplexer mit WHEN-ELSE ausgedrückt 1.5.1.2 „SELECT_WHEN“-Anweisung Die select_when Anweisung wird auch nebenläufig behandelt. Im Gegensatz zur when_else Anleitung haben die Abfragen keine Priorität. Die Reihenfolge in der sie vorkommen ist für die Bildung der Logik irrelevant. ENTITY mux IS PORT( a,b,c,d: IN std_logic_vector(3 DOWNTO 0); s: IN std_logic_vector(1 DOWNTO 0); OUT std_logic_vector(3 DOWNTO 0)); x: END mux; ARCHITECTURE comb OF mux IS BEGIN with s select x <= a WHEN "00", b WHEN "01", c WHEN "10", d WHEN OTHERS; END comb; Listing 1.18: Multiplexer mit SELECT_WHEN ausgedrückt 1.5.2 Sequenzielle (Sequential) Statements und Prozesse Ein Prozess enthält eine Reihe von Anweisungen, die in vertrauter Manier nacheinander, also sequentiell, ausgewertet werden. Die Reihenfolge der Anweisungen ist hier sehr wichtig. Demgegenüber werden alle Anweisungen, die ausserhalb eines Prozesses stehen, nebenläufig ausgeführt. Der Prozess selbst wird zusammen mit den anderen nebenläufigen Statements in einer Architektur aber „gleichzeitig“ behandelt, somit kann man sagen, dass der Prozess selbst ein nebenläufiges Statement ist. Die Signale eines Prozesses werden global erst nach Beendigung des Prozesses aktualisiert während Variablenzuweisungen sequentiell bearbeitet werden. 13 1 Die Hardwarebeschreibungssprache VHDL Dies ist aus der Sicht eines Programmierers zunächst ungewohnt. Geht man jedoch von der Hardware aus, so ist klar, dass dort alle Funktionseinheiten gleichzeitig, d.h. nebenläufig, arbeiten und auch die Signale nicht nacheinander, sondern zu beliebigen Zeiten ihren Wert ändern können. Abbildung 1.5 verdeutlicht diesen Unterschied an einem beispielhaften Vergleich. Nebenläufige und sequentielle Ausführung nebenläufig sequentiell Beginn Beginn Anweisung Anweisung Prozeß 1 Anweisung Prozeß 2 Anweisung Anweisung Anweisung Ende Ende Abbildung 1.5: Nebenläufige und Sequentielle Ausführung Prozesse werden bei der Simulation eines VHDL-Modells sequentiell abgearbeitet, entweder bis zum Prozess Ende oder bis zu einer wait-Anweisung. Diese gibt an, unter welchen Bedingungen der Prozess erneut aktiviert werden soll. Beispiel: procl: PROCESS (x) BEGIN a <= ’0’ IF x = "1011" THEN a <= ’1’, END IF; END PROCESS procl; Listing 1.19: Sensitivity Liste Prozesse stehen in der Architektur zwischen BEGIN und END Statement. Der Parameter (x) hinter dem Schlüsselwort PROCESS ist eine sogenannte Sensitivity List. Das bedeutet, dass der Prozess nur ausgeführt wird, wenn sich der Wert x ändert. Falls diese Sensitivity List weggelassen wird, wird der Prozess immer ausgeführt, wenn sich irgendein Signal ändert. Diese Liste kann auch mehrere Parameter enthalten und sollte alle Parameter enthalten die innerhalb des Prozesses abgefragt werden. Die Sensitivity Liste ist nur für den Simulator relevant, der Synthesizer betrachtet die Sensitivity Liste nicht. Die Idee hinter der Sensitivity Liste ist, Prozessorleistung bei der Ausführung von Simulationen zu sparen. Bei einer logischen Schaltung ändert sich das Ausgangssignal nur dann, wenn sich ein Eingangssignal ändert. 14 1.5 Verhaltensbeschreibung in VHDL Bei D-Flip Flops sogar nur nach der Flanke des Taktsignales. Also muss ein Prozess nur dann „aufwachen“, wenn sich ein Eingangssignal auf seiner Sensitivity Liste ändert. Alle anderen Prozesse können im „Schlafzustand“ bleiben wenn sich nichts an ihren Eingangsignalen ändert und somit wird Prozessorleistung gespart. Achtung: Aus oben genannten Gründen darf die Sensitivity Liste nicht benutzt werden um eine bestimmte Hardwarefunktionalität zu erzeugen. proc2: PROCESS (rst, clk) BEGIN IF rst=’1’ THEN q <= ’0’; ELSIF (clk’event AND clk=’1’) THEN q <= d; END IF; END PROCESS; Listing 1.20: D-FF mit asynchronem Reset Bei diesem Beispiel ist zu beachten, dass die Zuweisung q <= ’0’ nur erfolgt, wenn rst = ’1’ ist. Es gelten also genau die Regeln, die von den üblichen Programmiersprachen her bekannt sind. Der Ausdruck hinter „ELSIF“ (Aufpassen auf Schreibweise!) ist nur dann wahr, wenn eine ansteigende Taktflanke aufgetreten ist. Der obige Prozess beschreibt übrigens das Verhalten eines positiv flankengetriggerten D-Flip-Flops mit einem asynchronen Reset-Eingang. Prozesse strukturieren den VHDL Kode und erleichtern das Auffinden von Problemen, da der Kompiler Fehlermeldungen mit Hilfe von Prozessen referenziert. Um die Verständlichkeit und Übersichtlichkeit von VHDL Kode zu gewährleisten, sollte man für jede Funktion, Signal, Signalbündel oder ähnlich gesteuerte Signale jeweils immer einen eigenen Prozess verwenden. Kurz, man sollte nicht mit Prozessen sparen. 1.5.2.1 „IF_ELSIF“ im Prozess Schliesslich kann eine kombinatorische Logik auch mit Hilfe von Prozessen beschrieben werden; auch dabei haben wir die Wahl zwischen verschiedenen Anweisungen. Zunächst die Variante mit der IF _ ELSIF-Anweisung: ARCHITECTURE archmux OF mux BEGIN mx4: PROCESS (a,b,c,d,s) BEGIN IF s="00" THEN x <= ELSIF s="01" THEN x <= ELSIF s="10" THEN x <= ELSE x <= d; END IF; END PROCESS mx4; END archmux; IS a; b; c; Listing 1.21: Multiplexer mit IF_ELSIF ausgedrückt Die IF_ELSIF Anweisung ist analog zur when_else Anweisung priorisierend. Trifft eine Bedingung weiter oben zu, so kommen die nachfolgenden Bedingungen nicht mehr zur Ausführung. Die erste Zeile hat also Priorität gegenüber den nachfolgenden. Nach der Synthese liegen die Eingangssignale der ersten Bedingung näher am Ausgang als die der letzten Abfrage (Priorität). Das heisst es können je nach Signal unterschiedliche Verzögerungswerte der kombinatorischen Logik entstehen. 15 1 Die Hardwarebeschreibungssprache VHDL 1.5.2.2 Die „CASE_WHEN„Anweisung im Prozess ARCHITECTURE archmux OF mux IS BEGIN PROCESS (a,b,c,d,s) BEGIN CASE s IS WHEN "00" => x <= a; WHEN "01" => x <= b; WHEN "10" => x <= c; WHEN OTHERS => x <= d; END CASE; END PROCESS; END archmux; Listing 1.22: Multiplexer mit CASE Statement ausgedrückt Die case_when Anweisung ist wieder equivalent zur with_select Anweisung, nur dass sie nur im Prozess verwendet werden kann. Sie ist wieder nicht priorisierend, alle Abfragen werden gleich behandelt. Die case_when Anweisung benutzt man daher gerne für Adressdekoder da alle Eingangssignale gleich behandelt werden und deshalb die Durchlaufverzögerungen von den Eingängen zu den Ausgängen für alle Ausgangssignale weitgehend gleich sind. 1.5.2.3 Erzeugen von getakteten Flip-Flops D-Flip-Flops unterscheiden sich von RS-Flip-Flops durch ihre Taktflankensteuerung. Zur Modellierung muss ein Pegelübergang an einem Taktsignal erkannt werden, wozu sich das VHDL-Attribut EVENT eignet. Dieses Attribut bezieht man auf das Taktsignal und platziert es in einem Prozess entweder in einer WAIT- oder in einer IF-Anweisung: ARCHITECTURE reg OF dff IS BEGIN PROCESS (clk) BEGIN IF clk’EVENT AND clk = ’1’ THEN q <= d; END IF; END PROCESS; END reg; Listing 1.23: Erzeugen eines D-FF Zu beachten ist, dass gewünschte asynchrone Eingänge von Speicherelementen nicht automatisch von einem Syntheseprogramm erzeugt werden, sondern in VHDL beschrieben werden müssen. Am Beispiel eines D-Flip-Flops mit asynchronem Rücksetzeingang sei dies gezeigt: ENTITY dff_async_reset IS PORT (clk,d,reset: IN std_ulogic; q: OUT std_ulogic ); END dff_async_reset; ARCHITECTURE reg OF dff_async_reset IS BEGIN PROCESS (clk,reset) BEGIN IF reset = ’0’ THEN -- low-aktives Reset q <= ’0’; -- hat erste Prioritaet ELSIF clk’EVENT AND clk = ’1’ AND -- Abfrage auf Taktfl. clk’LAST_VALUE = ’0’ THEN -- nur, wenn kein reset 16 1.5 Verhaltensbeschreibung in VHDL q <= d; END IF; END PROCESS; END reg; Listing 1.24: DFF mit asynchronem Reset Zustandsdiagramm des Würfel-Zählers 1.5.2.4 Zähler in VHDL FolgeZustand Gegenwärtiger Zustand 2 3 1 4 6 5 Abbildung 1.6: Zustände eines Zählers mit 6 Schritten Zürcher Fachhochschule 16 Ein Zähler hat die Aufgabe Taktpulse zu zählen und ist mit zwei Blöcken aufgebaut. Der erste Block ist der Zustandsspeicher, in dem der gegenwärtige Zählerwert abgespeichert wird. Der zweite Block Prozesse Logik, des Zählers ist die Kombinatorischen die aus dem gegenwärtigen Zustand den Folgezustand berechnet. Der Folgezustand wird bei der nächsten Taktflanke in den Zustandsspeicher eingetragen. Da wir es mit zwei Funktionsblöcken zu tun haben, einer mit kombinatorischer Logik und einer mit getakteter Logik, macht es Sinn, diese in zwei separaten Prozessen unterzubringen. cnt_folge Prozess mit Kombinatorischer Logik 4 comb_ clk Prozess mit getakteter Logik reset reg_ cnt_gegenwart 4 Berechnung des Folgezustands Zustandsspeicher Zürcher Fachhochschule 20 Abbildung 1.7: Die zwei Prozesse des Zählers Der Ausgang der getakteten Logik ist der gegenwärtige Zustand und dient als Eingang der kombinatorischen Logik. Der Ausgang der kombinatorischen Logik ist der Folgezustand und dient als Eingang der getakteten Logik. Die kombinatorische Logik ist im wesentlichen eine Rechenschaltung, die zum gegenwärtigen Zustand 17 1 Die Hardwarebeschreibungssprache VHDL eine eins addiert. Beziehungsweise subtrahiert, wenn es sich um einen Downcounter handelt. Beliebige Abwandlungen davon sind in der kombinatorischen Logik programmierbar. Im folgenden VHDL Beispiel wird ein Zähler mit getrennten Prozessen gezeigt. In der Praxis findet man häufig auch Zähler, die nur mit einem Prozess aufgebaut sind, diese sind von der Funktion und vom Synthese Ergebnis identisch. Aus Gründen der Lesbarkeit und Klarheit des VHDL Codes, sollte man Zähler mit getrennten Prozessen beschreiben. LIBRARY ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; ENTITY zaehl_einfach IS PORT( clk,reset : IN std_logic; cnt_out : OUT std_logic_vector(3 downto 0) ); END zaehl_einfach; signal cnt_folge: signal cnt_gegenwart: integer RANGE 0 to 15; integer RANGE 0 to 15; BEGIN logik : PROCESS(cnt_gegenwart) BEGIN cnt_folge <= cnt_gegenwart + 1 ; END PROCESS logik; flip_flops : PROCESS(clk, reset) BEGIN IF reset = ’1’ THEN cnt_gegenwart <= 0; ELSIF clk’EVENT AND clk = ’1’ THEN cnt_gegenwart <= cnt_folge ; END IF; END PROCESS flip_flops; cnt_out <= std_logic_vector(to_unsigned(cnt_gegenwart,4)); Listing 1.25: Code Beispiel eines Zählers 1.5.2.5 Konvertierungsroutinen Da das Rechnen mit std_logic Vektoren nicht möglich ist, muss die Addition mit Integer Zahlen durchgeführt werden. Da jedoch der Zählerwert irgendwann einmal in einen Vektor umgewandelt werden muss, spätestens wenn man damit an die CPLD Pins gehen will, gibt es die IEEE Umwandlungsroutinen. Diese werden vom IEEE im Packet numeric_std (für std_logic Typen) zur Verfügung gestellt. Das folgende Beispiel wandelt einen Integer Wert cnt_gegenwart mit der Breite von 4 Bit zunächst in einen unsigned Wert um und dann in einen std_logic Vektor: cnt_out <= std_logic_vector(to_unsigned(cnt_gegenwart,4)); Listing 1.26: Umwandlung von Integer in std_logic_vector Manchmal muss man einen Vektor in einen Integer umzuwandeln. Dies ist zum Beispiel nötig, um einen Zähler mit dem Wert dieses Vektors vorzuladen. Das folgende Beispiel zeigt, wie ein Vektor zunächst in den Typ Signed und dann in Integer übertragen wird. 18 1.5 Verhaltensbeschreibung in VHDL Type Conversion std_logic_vector -> unsigned std_logic_vector -> signed unsigned -> std_logic_vector signed -> std_logic_vector integer -> unsigned integer -> signed unsigned -> integer signed -> integer integer -> std_logic_vector std_logic_vector -> integer unsigned + unsigned -> std_logic_vector signed + signed -> std_logic_vector numeric_std unsigned(arg) signed(arg) std_logic_vector(arg) std_logic_vector(arg) to_unsigned(arg,size) to_signed(arg,size) to_integer(arg) to_integer(arg) integer -> unsigned/signed ->std_logic_vector std_logic_vector -> unsigned/signed ->integer std_logic_vector(arg1 + arg2) std_logic_vector(arg1 + arg2) Resizing unsigned signed resize(arg,size) resize(arg,size) Tabelle 1.1: Mit numeric_std zur Verfügung stehende Convertierungsroutinen cnt <= to_integer(signed(data)); Listing 1.27: Umwandlung von std_logic_vector in Integer 1.5.2.6 Zustandsautomaten Bei der Modellierung von endlichen Zustandsautomaten (engl: Finite State Machines) (FSM) muss man zwischen Mealy-, Moore- und Medvedev-Automaten unterscheiden. Bei einem Mealy-Automaten hängt der Ausgangsvektor vom momentanen Zustand und vom Eingangsvektor ab, beim Moore-Automaten dagegen nur vom gegenwärtigen Zustand. Ein Medvedev-Automat ist dadurch gekennzeichnet, dass jeder Ausgang des Automaten mit dem Ausgang eines Zustands-Flip-Flops identisch ist. Beim werden die Ausgangsvektoren direkt weiterverwendet, er hat also keine Ausgangslogik. Abbildung 1.8 beschreibt ein Blockschaltbild für den Mealy-Automatentyp. 19 1 Die Hardwarebeschreibungssprache VHDL Mealy Automat Zustands -speicher Zt Zt+1 = δ (Zt, Et) Q n Et m Ansteuer Logik n δ !Q n = Anzahl der FFs At = ω (Zt,, Et) AusgangsLogik ω Takt Et = Eingangsvektor Z = Zustandssvektor zum gegenwärtigen Zeitpunkt t t Abbildung 1.8: Blockdiagram eines Mealy Automaten Zt+1 = Zustandssvektor nach dem Taktimpuls 18 Die folgenden drei VHDL-Prozesse zeigen die prinzipielle, synthesegerechte Modellierung eines MealyAutomaten. Die Blöcke aus Abbildung 1.8 sind hier in getrennten Prozessen realisiert. zustandsspeicher: PROCESS (clk, reset) BEGIN IF (reset = ’1’) THEN zustand <= reset_zustand; ELSIF (clk’event AND clk=’1’ AND clk’LAST_VALUE = ’0’) THEN zustand <= folge_zustand; END IF; END PROCESS zustandsspeicher; uebergangslogik: PROCESS (zustand, in1, in2, ...) BEGIN CASE zustand IS WHEN zustand1 => IF (in1 = ... AND in2 = ... AND ...) THEN folge_zustand <= ...; ELSIF ... ... WHEN zustand2 => ... END CASE; END PROCESS uebergangslogik; ausgabelogik: PROCESS (zustand, in1, in2, ...) BEGIN CASE zustand IS WHEN zustand1 => IF (in1 = ... AND in2 = ... AND ...) THEN out1 <= ...; out2 <= ...; ... ELSIF ... ... WHEN zustand2 => ... END CASE; END PROCESS ausgabelogik; Listing 1.28: Beispiel eines Mealy Automaten Da die Prozesse zur Beschreibung der Übergangslogik und der Ausgabelogik sehr ähnlich sind, können 20 1.5 Verhaltensbeschreibung in VHDL sie auch zusammengefasst werden. Eine mögliche Fehlerquelle hierbei ist, dass Latches für die Ausgänge erzeugt werden, wenn diese nicht in jedem Zustand und bei jeder Kombination der Eingangssignale einen Wert zugewiesen bekommen. Wenn man versucht, die FSM komplett in einem Prozess zu modellieren, der lediglich vom Takt und dem Rücksetzsignal getriggert wird, werden Flip-Flops für die Ausgänge erzeugt. Als Folgerung daraus kann man empfehlen, bei Mealy- und Moore-Automaten einen Prozess für die Zustandsspeicherung und einen weiteren Prozess für den rein kombinatorischen Teil zu verwenden. 21 1 Die Hardwarebeschreibungssprache VHDL 1.6 VHDL Kode zum Verifizieren von Schaltungen Gehen wir noch einmal zurück zu Kapitel 1.3.3.1 wo wir das Hierarische Design besprochen haben. Zum Verifizieren des ganzen Designs umbaut man dieses noch einmal in einer höhere Hierarchie die wir Testbench nennen. Die Testbench ist die höchste Hierarchiestufe in einem Design. In ihr enthalten ist das zu testende Teil. In der Fachsprache nennt man dies „Device under test“ oder DUT. Testet man ein ganzes System, so ist das DUT der Top Level eines Designs. Die Testbench schliesst dann direkt an die Pins des CPLDs an. Testet man nur einen Unterblock, so ist das DUT der Unterblock. Da die Testbench immer die höchste Hierarchiestufe ist und darüber keine weiteren Blöcke existieren, hat die Testbench Entity auch keine Verbindungen nach aussen. Die Testbench Entity ist somit leer. ENTITY testbench IS END testbench; Listing 1.29: ENtity einer Testbench Eine Testbench die so aufgebaut ist hat den Vorteil, dass der Toplevel nach der Synthese anstelle des unsynthetisierten Kodes eingesetzt werden kann und die Simulation damit wiederholt werden kann. Vor der Synthese enthält die Testbench den unsynthetisierten RTL Kode. Nach der Synthese kann man den TOP Level des unsynthetisierten RTL Kode mit dem fertig synthetisierten Kode einfach austauschen. Die Simulationsergebnisse müssen danach gleich sein, ausser dass jetzt die Timing Informationen vorhanden sind. Dass heisst unsynthetisiertes RTL kann man mit beliebigen Taktfrequenzen laufen lassen. Synthetisierte Designs laufen nur noch bis zu Ihrer maximalen Taktfrequenz. Man nennt die Simulation nach der Synthese mit den Timingwerten auch Timingsimulation oder „Backannotierte“ Simulation, da die Werte für das Timing im nachhinein angefügt wurden. 1.6.1 Architecture der Testbench Im Architecture Teil der Testbench wird der Top Level als Component deklariert, es ist also ein Block der in der Architecture „Testbench“ verwendet wird. Da es sich um den Toplevel handelt gibt es sonst meist keine weiteren Component. Nach dem „Begin“ der Architecture muss dann die Component Top-Level an die Signale in der Architectur angeschlossen werden. Das geschieht mit dem Port Map. Für jeden Anschluss an den Device under Test Component muss vor der „Begin“ Section ein Signal deklariert werden. Nach dem Port Map des DUT folgt die Erzeugung der Stimuli und eventuell die Assert Statements. Um eine Dummy Tetbench Architektur herzustellen gibt es im Quartus einen Testbenchwizzard. 1.6.2 Erzeugung von Takten Um ein Taktsignal zu erzeugen bedient man sich eines Prozesses. Da ein Prozess ohne Sensitivity Liste immer aktiv ist, beginnt der unten gezeigte Prozess nach Ablauf der zwei WAIT statements wieder von vorne (siehe Abschnitt 1.5.2). CLK_HALFP ist ein Signal vom Type Time. signal clk_halfp : time := 20 nS; BEGIN clkgen : PROCESS BEGIN 22 1.6 VHDL Kode zum Verifizieren von Schaltungen WAIT FOR 1*clk_halfp; clk <= ’0’; WAIT FOR 1*clk_halfp; clk <= ’1’; END PROCESS clkgen; Listing 1.30: Erzeugen eines Taktes 1.6.3 Assert Statements Assertions dienen zur Überprüfung von Bedingungen und zur Ausgabe von Warnungen bzw. Fehlermeldungen. Die Syntax lautet: [assert_label :] ASSERT condition [ REPORT "message_string"] [ SEVERITY severity_level] ; Listing 1.31: Melden von Simulationsfehlern Diese Syntax wird folgendermassen interpretiert: „Überprüfe, ob die Bedingung condition erfüllt ist; falls nicht, erzeuge die Meldung „message_string“ und breche, abhängig von der Fehlerklasse severity_level, gegebenenfalls die Simulation ab.“ Eine Fehlermeldung mit evtl. weiteren Konsequenzen tritt also nur auf, falls die angegebene Bedingung (condition) den Wert false ergibt. Ohne Angabe der Fehlermeldung wird der String „Assertion violation.“ ausgegeben. Die vier möglichen Fehlerklassen (entsprechend dem vordefinierten Aufzähltyp severity_level) haben folgende Bedeutung: • note dient zur Ausgabe von allgemeinen Informationen, • warning dient zur Anzeige von möglichen unerwünschten Bedingungen, • error zeigt an, dass eine Aufgabe mit dem falschen Ergebnis abgeschlossen wurde, • failure zeigt an, dass eine Aufgabe nicht abgeschlossen werden Wird in der Anweisung keine Fehlerklasse angegeben, so wird sie mit der Klasse error versehen. Die Entscheidung, ab welcher Klasse die Simulation abgebrochen wird, legt man i.d.R. durch eine spezifische Simulatoreinstellung fest. Zwei Beispiele zur Anzeige eines (low-aktiven) Resetsignals und zur Prüfung auf definierten Pegel eines Signals sig_a vom Typ std_ulogic lauten: reset_check : ASSERT sig_reset /= ’0’ REPORT "Achtung: Reset ist aktiv !" SEVERITY note ; Listing 1.32: Prüfen des Signals sig_reset ASSERT (now = 0 fs) OR (sig_a /= ’U’) REPORT "sig_a ist nicht initialisiert !" ; Listing 1.33: Unterdrückung der Fehlermeldung am Anfang der Simulation Im zweiten Beispiel wird die Ausgabe einer Fehlermeldung zum Zeitnullpunkt unterdrückt. 23 2 CPLD Design Flow 2 CPLD Design Flow 2.1 Einrichten von Lizenzen auf Windows XP Im Labor sind die Lizenzen bereits eingerichtet, falls sie die Lizenzen auf ihren eigenen PC installieren wollen, verfahren sie wie folgt: • Zunächst müssen sie eine Umgebungsvariable LM_LINCENSE_FILE auf ihrem Windows XP einrichten: 1. Start-> Systemsteuerung -> Leistung und Wartung -> System ->Erweitert -> Umgebungsvariablen 2. Einstellen der Umgebungsvariablen LM_LICENSE_FILE 7172:rizzo.zhwin.ch; 7175@rizzo.zhwin.ch • Einstellen der Umgebungsvariablen zum Abfragen des Lizenzservers: 1. Einstellen zur Abfrage des Lizenz Fileservers am ModelSim Start -> ModelSim SE 6.0B -> Licensing Wizzard -> Continue 2. Im Feld Port Nummer und Servername eingeben: 7175@rizzo.zhwin.ch -> OK 3. Der License Wizard wird fragen LM_LICENSE_FILE = 7175@rizzo.zhwin.ch als Umgebungsvariable einzufügen. Dies mit „JA“ bestätigen. 4. Eine Fehlermeldung, dass der Checkout Test nicht erfogreich war könnte erscheinen, dies kann ignoriert werden. 24 2.2 Arbeiten mit dem Mentor ModelSim Simulator 2.2 Arbeiten mit dem Mentor ModelSim Simulator 2.2.1 Anlegen einer Verzeichnissstruktur edaverzeichnis Projekt simulation source synthese .vhdl modelsim work scripts .do Abbildung 2.1: Typische Unterverzeichnisse in einem Projekt Setzen sie für jede Übung (Projekt) eine eigene Projekt Verzeichnissstruktur auf. Dies schafft Ordnung und verhindert, dass zufällig gleiche Entity Namen von alten Projekten im Work Verzeichniss den Simulator durcheinander bringen. ACHTUNG: Dateien, Signalnamen und Verzeichnisse dürfen keine Umlaute oder Sonderzeichen haben, da ModelSim nur auf 7-bit ASCII ausgelegt ist. Ein Projektverzeichnis könnte man in drei Unterverzeichnisse aufteilen: • source: Hier speichern sie den VHDL Code und die Testbench ab. • synthese: Hier speichern sie alle in Zusammenhang mit der Synthese notwendigen Verzeichnisse. • Simulation: Hierhin legen sie alle in Zusammenhang mit der Simulation notwendigen Verzeichnisse. • scripts: Bei der Simulation stehen hier die compile.do und wave.do. scripte welche die Kompilierung starten und die Waveform aufrufen. Bei der Synthese stehen hier die Scripts für die Constraints und Pin Zuweisungen. • modelsim: Hier drin „Arbeitet“ das ModelSim. Beim Einrichten eines Projektes fragt sie Modelsim nach einem Working Directory. Modelsim legt hier seine temporären Verzeichnisse ab. Es ist gut diese Verzeichnisse nicht mit den Verzeichnissen die sie selbst generiert haben zu vermischen. So können sie temporäre Verzeichnisse zum löschen schnell identifizieren. Ausserdem können sie dem Check-In Tool verbieten dieses Verzeichnis mit in den Vault zu nehmen. Das spart Speicherplatz und Ein- und Auscheckzeit. Als Regel sollten alle mit den Tools Reproduzierbaren Dateien 25 2 CPLD Design Flow nicht eingechecked werden. • quartus: Hier drin „Arbeitet“ das Quartus. Beim Einrichten eines Projektes fragt sie Quartus nach einem Working Directory. Quartus legt hier normalerweise die Syntheseergebnisse wie Konfigurationsdateien etc. ab. Leitet man die Syntheseergebnisse in das Verzeichniss netlist um, so kann man durch nicht einchecken dieses Verzeichnisses Platz und Zeit sparen. • netlist: Hier könnte man alternativ die Syntheseergebnisse ablegen. Zum Beispiel die Netzliste zum Nachsimulieren. 26 2.2 Arbeiten mit dem Mentor ModelSim Simulator 2.2.2 Vorbereiten eines „compile.do“ files für VHDL simualtion (vor der Synthese) Aus Gründen der Reproduzierbarkeit von Ergebnissen und einer besseren Dokumentation ist es von Vorteil, Arbeitsabläufe in Scripten unterzubringen. Im compile.do script stehen alle Simualtorbefehle die zum kompilieren und simulieren eines Projektes nötig sind. Nach eingeben der Kommandozeile do compile.do im Simulator Ausgabefenster wird dann nacheinander Kompiler, Simulator und Waveform Window aufgerufen. Die compile.do Datei wird direkt in der Datei simulation/scripts untergebracht und ist folgendermassen aufgebaut: • Zunächst wird mit dem Kommando VLIB die Ziel-Library „work“ definiert. Dort legt der Kompiler die kompilierten VHDL Dateien ab. • Mit VCOM werden die VHDL Dateien kompiliert, der Pfad zu den VHDL source Dateien ist relativ angegeben. • Danach wird mit dem Kommando VSIM die Simulation gestartet. Der Simulator bezieht seine Daten aus der Library work. Die kompilierten VHDL Verzeichnisse sind darin als work.<testbench_architektur_name> abgelegt. • Der wave.do file öffnet das Waveform Fenster nach der Kompilation automatisch. Das Erzeugen der wave.do lässt man am einfachsten vom ModelSim selbst besorgen. Die Beschreibung dafür steht in Kapitel 2.2.4 • Das „Run“ Kommando lässt den Simulator für 100ns laufen. LUT mit zwei Eingängen # create work library vlib work # compile project files vcom -2002 -explicit -work work ../source/dff_srst.vhd vcom -2002 -explicit -work work ../source/testbench_dff_srst.vhd # run the simulation #work.entityname muss mit Entity der Testbench übereinstimmen vsim -t 1ns -lib work work.testbench_dff_srst #Öffnen der Waveform Fenster mit den richtigen Signalnamen do ../scripts/wave.do run 100.0 ns Listing 2.1: Das compile.do script 2.2.3 Aufsetzen eines ModelSim Projektes 1. Nachdem sie die notwendigen Verzeichnisse erzeugt haben, starten sie ModelSim 2. Starten sie den „new project wizard“ mit File -> New -> Project. Wählen Sie als Projekt Arbeitsverzeichnis <projekt>/simulation/modelsim. VHDL wird ähnlich wie die C-Programmiersprache kompiliert. Aus diesem Grund gibt es bei VHDL Quell- und Zieldateien. Die Zieldatei bei der VHDL Kompilation nennt sich die „work library“. In der work library befinden sich die bereits kompilierten VHDL Dateien. Ändert sich eine VHDL Datei in einem Design mit mehreren VHDL Dateien so müssen nicht alle VHDL immer wieder neu compiliert werden, sondern nur das welches sich geändert hat. Dies hat den Vorteil von Kompilationszeitersparnis bei grösseren Designs. Die work library wird beim Aufsetzen des 27 2 CPLD Design Flow Projektes festgelegt. ACHTUNG: Wenn sie Verschieden Übungen immer wieder in der gleichen work library ausführen, kann es sein, dass darin noch Dateien von vorangegangen Übungen stehen, die mit den neuen Übungen interferieren. Deshalb macht es Sinn, ab und zu einmal die work library zu löschen. Vor der Kompilation beziehen sich die Dateinamen auf die VHDL Dateinamen. Nach der Kompilation im work Verzeichnis beziehen sich die Dateien auf den Namen der Entity/Architektur Namen, die VHDL Dateinamen sind dann irrelevant. Dies ist eine häufige Fehlerquelle bei der Kompilation. Damit man sich besser orientieren kann, nennt man die VHDL Dateien (.vhdl) am besten genauso wie die Entities. Frei wählbarer Projektname Pfad zu Projekt Simulationsverzeichniss Library Name, wohin VHDL kompiliert wir Abbildung 2.2: Festlegen des Arbeitsverzeichnisses in dem Modelsim läuft 28 2.2 Arbeiten mit dem Mentor ModelSim Simulator Achtung: Beenden sie das Einrichten an dem Punkt, wo sie der Setup Wizzard nach den Source files fragt. Laden sie keine Source VHDL files ins ModelSim, denn dies wird später von ihrem compile.do Script automatisch erledigt. Keine VHDL Files importieren, sondern close drücken Abbildung 2.3: Festlegen des Arbeitsverzeichnisses in dem Modelsim läuft 3. Nachdem Modelsim geöffnet ist, brauchen sie nur das Kommando do ../scripts/compile.do in die Ausgabeleiste des Simulators eingeben. Beachten sie, dass sich die compile.do Datei in einem anderen Verzeichnis als das Arbeitsverzeichnis des Simulators befindet, deshalb: do ../scripts/compile.do 4. Wenn die VHDL Dateien keine Fehler mehr haben, dann sehen die Simulatormeldungen wie unten aus. Trotzdem erscheint nach dem Aufruf der wave.do Datei noch ein Fehler. Der Fehler rührt daher, dass beim ersten Mal noch kein wave.do Verzeichnis existiert. Als nächstes muss die wave.do Datei wie in Kapitel 2.2.4 beschrieben erzeugt werden. do ../compile.do # ** Warning: (vlib-34) Library already exists at "work". # Model Technology ModelSim SE vcom 6.1d Compiler 2006.01 Jan 23 2006 # -- Loading package standard # -- Loading package std_logic_1164 # -- Loading package std_logic_arith # -- Compiling entity bcd_decoder_when # -- Compiling architecture comb of bcd_decoder_when # Model Technology ModelSim SE vcom 6.1d Compiler 2006.01 Jan 23 2006 # -- Loading package standard # -- Loading package std_logic_1164 # -- Compiling entity tb_bcd_decoder_when # -- Compiling architecture struct of tb_bcd_decoder_when # vsim -lib work -t 1ns work.tb_bcd_decoder_when 29 2 CPLD Design Flow # # # # # # # # Loading C:\Modeltech_6.1d\win32/../std.standard Loading C:\Modeltech_6.1d\win32/../ieee.std_logic_1164(body) Loading work.tb_bcd_decoder_when(struct) Loading C:\Modeltech_6.1d\win32/../ieee.std_logic_arith(body) Loading work.bcd_decoder_when(comb) ** Error: Cannot open macro file: ../wave.do Error in macro ./../compile.do line 11 Cannot open macro file: ../wave.do Listing 2.2: Compilierung ist richtig, aber es fehlt noch das wave.do 2.2.4 Generieren eines wave.do files Kompilieren sie Ihre VHDL files mit Hilfe des compile.do Scriptes wie im Kapitel 2.2.2 und ignorieren sie die Fehlermeldung über die fehlende wave.do Datei. Zunächst müssen sie die Signale, die sie beobachten wollen, von Hand öffnen. Das geschieht indem sie die zu betrachtenden Signale im „Objects“ Fenster (Mitte oben)selektieren und danach mit der rechten Maustaste „Add to wave -> selected signals“ anwählen. Jetzt sollte das Waveformwindow erscheinen. Falls Sie ein hierarchisches Design haben, können Sie im „Workspace“ Fenster(Oben links) auch jedes Signal der darunterliegenden Blöcke zur Betrachtung anwählen. Nachdem sie die gewünschten Signale angewählt haben, können sie das Waveform Fenster mit „File -> save“als wave.do abspeichern. Legen sie wave.do im Verzeichnis simulation/scripts ab. Starten Sie die Simulation jetzt noch einmal mit do ../compile.do jetzt wird das Waveformfenster automatisch geöffnet und die Simulation wird gestartet. 30 2.2 Arbeiten mit dem Mentor ModelSim Simulator 2.2.5 Simulationswarnungen Erscheint die Warning: Component xyz is not bound, heisst dies, dass der Simulator die korrekt compilierten VHDL Komponenten auf einer oberen Hierarchieebene nicht miteinander verbinden konnte. Der Bindeprozess erfolgt mit Komponenten die schon kompiliert sind, d.h. die Dateien müssen im Work Verzeichnis vorhanden sein. Die Kompilation der einzelnen VHDL Dateien war zwar erfolgreich, aber die Komponenten passen nicht zusammen wie in der Toplevel Komponente beschrieben. Möglicherweise gibt eine Diskrepanz bei den Entity Namen. Im Top Level wurde eine Entity definiert, diese ist aber im Work Verzeichnis nicht oder unter einem anderen Namen vorhanden. Es kann auch sein, dass im Top Level Signale verbunden werden, die auf Entity Ebene gar nicht existieren. 2.2.6 Backannotierte Simulation Um backannotiert zu simulieren müssen sie wie folgt vorgehen: 1. Damit Laufzeitverzögerungen des CPLDs bei der Simulation berücksichtigt werden, benötigt der Synthesizer zusätzlichen Dateien welche die Laufzeitverzögerungen beinhalten. Diese generiert der Synthesizer aber nur wenn er dazu aufgefordert wird. Um den Synthezizer zu veranlassen diese Dateien zu generieren gehen sie in: Assignmnets -> Settings. 2. Wählen sie dort den Tab: EDA Tool Settings -> Simulations 3. Dort müsssen sie drei Parameter einstellen: • Das Simulationswerkzeug: Modelsim • Die Sprache: VHDL • Das Verzeichnis, wo die Ergebnisse der Synthese abgespeichert werden. Wenn sie konsequent sind und sich an Abschnitt 2.2.1 halten, dann sollten diese Verzeichnisse unter projekt/synthese/netlist abgespeichert werden. 31 2 CPLD Design Flow Abbildung 2.4: Generieren der Delay Werte für Backannotierte Simulation • Bereiten sie im Verzeichnis simulation/scripts Script z.B. doba.do vor, welches die Kompilationen für die backannotierte Simulation automatisch ausführt. vlib work #This line must be run only once do ../script/altera.do vcom -work work ../../synthese/netlist/lauflicht_top.vho # Testbench vcom -2002 -explicit -work work ../../source/tb_lauflicht_top.vhd #simulation: back annotation vsim -sdftyp dut=../../synthese/netlist/lauflicht_top_vhd.sdo -t 1ps work. tb_lauflicht_top do ../../script/wave.do run 1000.0 ns Listing 2.3: Script für Simulation mit Backannotation Erklärung zum doba.do Script: • do ../scripts/altera.do Dieses Kommando Kompiert Altera Cyclone II spezifische Libraries. • vcom -work work ../../synthese/netlist/lauflicht_top.vho Kompiliert das Syntheseergebnis vom Design lauflicht_top • vcom -2002 -explicit -work work ../../source/tb_lauflicht_top.vhd Kompiliert die Testbench von Lauflicht • vsim -sdftyp dut=../../synthese/netlist/lauflicht_top_vhd.sdo -t 1ps work.tb_lauflicht_top Startet die Simulation unter Einbindung des Timing Delay files lauflicht_top_vhd.sdo. DUT ist der Name für die Instanziierung des Designs. 4. Lassen sie das Script im ModelSim Command Window mit do ../script/doba.do ablaufen. 32 2.3 Aufsetzen einer CPLD Synthese mit Altera Quartus 2.3 Aufsetzen einer CPLD Synthese mit Altera Quartus 2.3.1 Aufsetzen eines Quartus Projektes 1. Erstellen sie in ihrem Projektverzeichnis, dass sie schon unter 2.2 eröffnet haben, auch ein Verzeichniss <projekt>/snthese/quartus. Das Verzeichniss quartus ist das Arbeitsverzeichniss für das Synthesizerprogramm. 2. Starten sie Quartus und Starten sie den New Project Wizard File -> New Project Wizard. Füllen sie die Dialogbox folgendermassen aus: • Working Directory for the Project: <projekt>/synthese/quartus • Name of the Project: Frei wählbarer Projektname • What is the name of the top level of the project: VHDL File der obersten Hierarchiestufe (aber unterhalb der Testbench, denn es macht keinen Sinn diese zu synthetisieren) aus dem Verzeichnis <project>/vhdl. • -> NEXT NRD Abbildung 2.5: Einstellen des Arbeitsverzeichnises 3. Quartus verlangt jetzt nach Ihren Source VHDL Dateien. Diese liegen in <project>/source (Die Testbench wird nicht mit synthetisiert). -> ADD -> NEXT 4. Im nächsten Menuepunkt wird der CPLD Baustein ausgewählt. Die Grösse des CPLD, das ver- 33 2 CPLD Design Flow wendete Gehäuse und die Betriebsspannung werden hier festgelegt. Wählen sie den CPLD Typ EPM2210F324C3 der Max II Serie -> NEXT Abbildung 2.6: Wählen des CPLDs 5. Die EDA Tool Settings sind wichtig, wenn sie nach der Synthese mit anderen EDA Tools weiterarbeiten wollen. Der Synthesizer erzeugt anhand dieses Formulars die Dateien die für andere EDA tools notwendig sind. Wir wollen unser CPLD nach der Synthese mit ModelSim nachsimulieren. Deshalb wählen wir hier: Simulation Tool: ModelSim(VHDL) -> NEXT 34 2.3 Aufsetzen einer CPLD Synthese mit Altera Quartus Abbildung 2.7: Wählen des Mentor Graphics EDA tools 6. Im letzten Menuepunkt habe sie noch einmal die Gelegenheit alle Einstellungen zu kontrollieren (Beachten sie bei den Dateinamen dass keine Umlaute möglich sind) dann klicken sie dann auf -> FINISH Von jetzt ab ist dieses Projekt mit File -> Open Project immer wieder abrufbar. Die Projekteinstellungen können immer noch jederzeit geändert werden. 2.3.2 Hinzufügen oder Entfernen von Dateien aus einem Projekt 1. Unter Assignments -> Settings Eintrag File können weitere VHDL Dateien aus dem Source Verzeichnis dazugefügt oder entfernt werden. 2. Achtung: Falls sie einen neuen Top Level File definieren, müssen sie diesen unter Assignments -> Settings General registrieren. 2.3.3 Starten der Synthese Wir starten unsere erste Synthese unter Processing -> Start Compilation. Zunächst werden wir einmal ohne Constraints kompilieren, aber in der Zukunft werden wir an diesem Punkt noch einige Einstellungen vornehmen müssen. Nach erfolgreicher Synthese muss die Anzahl der Fehler Null sein! 35 2 CPLD Design Flow 2.3.4 Auswerten der Berichte nach Synthese Place und Route Nach der Synthese sollten folgende Punkte überprüft werden: • Anzahl der Errors muss null sein. • Jede Warnung muss erklärbar sein. Gefährliche Warnungen sind Hinweise über unbeabsichtigte Register. Fehlende Einträge in der Sensitivity Liste von Prozessen, denn dann kann die Simulation von der tatsächliche Hardwareimplementierung abweichen. • Prüfen sie, ob im Verzeichnis <projekt>/synthese/quartus/simulation/modelsim die datein .sdo, .vho und .xrf vorhanden sind, diese brauchen sie um später eine backannotierte simulation durchzufühern. Falls diese nicht vorhanden sind, ist es wahrscheinlich, dass sie beim Einrichten der Synthese keine EDA Tools angegeben haben. • Mit dem „Resource Optimization Advisor“ in Tools können sie einen Kompilationsreport anzeigen lassen. Vor Ihrem Design sollten sie sich immer überlegen, wie viele Flip-Flops und wie viele I/O Pins Ihr Design benötigt, diese Zahlen können sie mit dem Resource Advisor überprüfen. Die Ausnutzung des Bauteils ist ein Wichtiger Aspekt. Ist die Ausnutzung höher als 80%, so ist wahrscheinlich, dass bei einer Designänderung und gelockten Pins kein Fit mehr erreicht werden kann oder das Timing nicht mehr die erforderlichen Zeiten erfüllt. • Mit dem „RTL Viewer“ kann ein Schaltplan dargestellt werden. Es ist ratsam den Schaltplan kurz zu inspizieren und zu prüfen ob er im grossen und Ganzen Sinn macht. • Im „Technology Map Viewer“ sieht man die tatsächliche Implementierung in die Logik Elemente. 2.3.5 Zuweisen von I/O Pins Gibt man keine Pin location assignmnent Constraints an, so bestimmt das Placement Tool von selbst welche Signale es an welche I/O Pins am besten legt. Dies ist abhängig von den eingegebenen Constraints und an welcher Stelle sich die Funktionsblöcke im Layout befinden. Solange man die Pinzuweisung nicht festlegt, können sich bei jeder neuen Kompilierung die Anordnung der I/O Pins verändern. Wenn die Platine aber bereits hergestellt wurde, ist dies unakzeptabel. Deshalb ist es möglich, dem I/O Placement Tool die Pinzuweisungen vorzugeben. Es empfiehlt sich dies aber erst möglichst nach Fertigstellung des VHDL Designs zu machen, da sonst der Ausnutzungsgrad und das Timing beeinflusst werden kann. Das Kommando zum Festlegen der vom Placer gefundenen Pinzuweisungen befindet sich in: Assignments -> Backannotate Assignmnets Bei Ausführen dieses Kommandos wird im Hintergrund zum Beispiel folgende TCL Zeile ausgeführt: set_location_assignment PIN_Y3 -to decled[7] ausgeführt. Selbstverständlich kann man diese Location Assignmnet Kommandi für seinen peronalisierten TCL file übernehmen. So hat man Gelegenheit einige der PIN-Location selbst zu manipulieren, um zum Beispiel das Platinenlayout zu vereinfachen. Dies könnte sich aber negativ auf das Timing des CPLD auswirken. Deshalb ist es ratsam nach ändern von Pin-Locations von Hand, das CPLD Timing zu überprüfen. 36 Literaturverzeichnis [GL94] G UNTHER L EHMANN, Manfred S.: Schaltungsdesign mit VHDL. Franzis, 1994 [Pel96] P ELLERIN, David: VHDL Made Easy. Prentice Hall, 1996. – 400 S 37