VHDL Kurzbeschreibung

A. Mäder

Universität Hamburg – Fachbereich Informatik Arbeitsbereich Technische Grundlagen der Informatik

Inhaltsverzeichnis

1 Konzepte von VHDL 1 1.1 Grundkonzepte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Design-Paradigmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Bibliotheken und compilierbare Einheiten . . . . . . . . . . . . . . . . . . . 2

1.3.1 Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3.2 Entity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3.3 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.3.4 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.4 zeitliche Kontrolle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2 Datentypen 9 2.1 Skalare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.2 komplexe Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.3 Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3 Bezeichner und Deklarationen 19

4 Ausdrücke 21

5 Sequentielle Beschreibungen 24 5.1 Anweisungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 5.2 Unterprogramme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

6 Signale 34 6.1 Deklaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 6.2 Signalzuweisungen im Prozeß . . . . . . . . . . . . . . . . . . . . . . . . . 35 6.3 Implizite Typauflösungen und Bustreiber . . . . . . . . . . . . . . . . . . . 36 6.4 Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

7 Konkurrente Beschreibungen 41

8 Strukturbeschreibungen 45 8.1 Erzeugung von Instanzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 8.2 Benutzung von Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 8.3 Konfigurationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 8.4 Parametrisierung durch generische Werte . . . . . . . . . . . . . . . . . . . 51

9 Libraries und Packages 54

10 VHDL und Synthese 57

10.1 Synopsys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 10.1.1 Behandlung von Beschreibungsformen in der Synthese . . . . . . . . 60 10.1.2 VHDL-Prozesse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 10.1.3 Endliche Automaten . . . . . . . . . . . . . . . . . . . . . . . . . . 69 10.1.4 Zusätzliche Information . . . . . . . . . . . . . . . . . . . . . . . . 71

A Syntaxbeschreibung 72 A.1 Übersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 A.2 Bibliothekseinheiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 A.3 Deklarationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 A.4 Spezifikationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 A.5 Bibliotheksbenutzung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 A.6 sequentielle Anweisungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 A.7 konkurrente Anweisungen . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 A.8 Vordefinierte Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 A.9 Reservierte Bezeichner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

Literatur 119

Syntax-Index 120

1 Konzepte von VHDL

VHDL ist eine Hardwarebeschreibungssprache; dabei steht der Name für: VHSIC Hardware Description Language Very High Speed Integrated Circuit

VHDL wurde 1983 vom amerikanischen Department of Defense initiiert und ist seit Ende 1987 als IEEE Standard 1076 genormt. Inzwischen ist VHDL die quasi Standard-Hardware-beschreibungssprache.

1.1 Grundkonzepte

Die Sprache VHDL dient der Beschreibung und Simulation digitaler Systeme (ASICs) und deren Umgebung. Alle, während des Entwurfsvorgangs anfallenden Beschreibungen der Schaltung, werden von Sprachumfang abgedeckt. Dabei ist die Schaltung jederzeit simulierbar. Dementsprechend sind in VHDL die folgenden Konzepte verwirklicht:

Hierarchie: die Unterteilung des Entwurfs in (Teil-)Komponenten wird unterstützt. Der Gesamtentwurf wird dann hierarchisch aus diesen Teilen zusammengesetzt. Die Komplexität dieser Teile kann vom einfachen Gatter (z.B. NAND) bis hin zu komplexen Funktionseinheiten (z.B. Prozessorkern) reichen.

Abstraktion: jede Design-Einheit (Entity) kann auf unterschiedliche Weise beschrieben sein. Dabei ist grundsätzlich zwischen folgenden Möglichkeiten zu unterscheiden: Verhalten : Algorithmische Beschreibung mit den Mitteln einer höheren Program-

miersprache.

Datenfluß : Mischform zwischen Struktur- und Verhaltensbeschreibung. Beschreibt die Struktur von Datenpfaden, während die Operationen auf den Daten als elementare Funktionen vorhanden sind.

Struktur : Darstellung der strukturellen Verbindung von Elementen im Sinne einer

Hierarchie.

Durch die Definition benutzereigener Datentypen kann die Aufgabe unabhängig von konkreten Hardwarerealisierungen spezifiziert werden.

Datenhaltung: das in der Sprache benutzte Bibliothekskonzept erlaubt:

den Zugriff auf gemeinsame Datenbestände durch Arbeitsgruppen

die Wiederverwendung bestehender (Teil-)Entwürfe

das Einbinden herstellerspezifischer Bibliotheken (z.B. für Standardzellen)

1.2 Design-Paradigmen

Der eigentliche Design-Prozeß, bei Verwendung von VHDL, entspricht einem Top-Down Vorgehen.

Algorithmendesign: Ausgangspunkt ist die Verhaltensbeschreibung der Schaltung, deren Funktionalität durch Simulationen geprüft wird. So können verschiedene Algorithmen implementiert und miteinander verglichen werden.

Auf oberster Ebene ist dies eine Beschreibung der zu entwerfenden ICs oder Systems, sowie eine Testumgebung, die das Interface zu der Schaltung darstellt.

Top-Down Strukturierung: Im weiteren Vorgehen wird die Schaltung in Funktionsblöcke gegliedert, bis man letztendlich eine Strukturbeschreibung erhält.

Dieser Prozeß — Algorithmischer Entwurf von Funktionseinheiten, hierarchische Verfeinerung und Umsetzung in Strukturbeschreibungen — wird rekursiv ausgeführt, bis man letztendlich bei Elementen einer Zellbibliothek angekommen ist und die Schaltung praktisch realisiert werden kann.

Dadurch, daß die Schnittstelle der Schaltung und deren eigentliche Realisierung voneinander getrennt sind, werden Alternativen im Entwurf unterstützt — exploring the designspace.

Durch den Einsatz von Synthesewerkzeugen wird die Entwurfsaufgabe (auf den unteren Abstraktionsebenen) dabei zunehmend vereinfacht: ausgehend von Verhaltensbeschreibungen werden Netzlisten für Zielbibliotheken generiert. Derzeitiger Stand der Technik ist, daß die Synthese für Logik (Schaltnetze) und für endliche Automaten problemlos beherrscht wird. Für die Synthese komplexerer Algorithmen gibt es viele gute Ansätze, die zumindest bei Einschränkungen auf bestimmte Anwendungsfelder (Einschränkung des Suchraums), mit den Entwürfen guter Designer konkurrieren können.

1.3 Bibliotheken und compilierbare Einheiten

Die Entwürfe sind in Bibliotheken organisiert, wobei die Bibliotheken jeweils compilierten und durch den Simulator ausführbaren VHDL-Code enthalten. Bibliotheken können folgende vier Teile enthalten:

package  : globale Deklarationen
entity  : Design – Sicht von Außen (black box)
architecture : Design Implementation
configuration : Festlegung einer Design-Version (Zuordnung: entity – architecture)

Neben herstellereigenen- und benutzerdefinierten Bibliotheken gibt es zwei Standardbibliotheken: WORK : default-Bibliothek des Benutzers. Wenn nichts anderes angegeben wird, ist WORK

die Bibliothek, mit der der VHDL-Compiler und -Simulator arbeiten. STD : enthält die beiden Packages STANDARD und TEXTIO mit vordefinierten Datentypen

und Funktionen.

Compilation und Simulation VHDL-Beschreibungen werden in zwei Schritten bearbeitet:

1. Die Analyse (Compilation) prüft die Syntax und die Konsistenz des VHDL-Codes und schreibt die Ausgabe in die entsprechende Bibliothek (normalerweise WORK).

Bei Verwendung von SYNOPSYS: vhdlan.

2. Bei der Simulation von Elementen wird dann die Funktion der eigegebenen Schaltung überprüft.

Bei Verwendung von SYNOPSYS: vhdlsim, vhdldbx.

Benutzung von Bibliothekselementen VHDL Bibliotheken erlauben bis zu drei Namensebenen:

lib name.package name.item name : volle Derefenzierung
lib name.item name  : bei Eindeutigkeit von item name
item name  : Bibliothek WORK, Eindeutigkeit von item name

Um Bibliothekselemente im eigenen VHDL-Entwurf benutzen zu können, muß zuerst die Bibliothek definiert werden (library lib name), anschließend kann die Auswahl von Packages aus den Bibliotheken erfolgen (use lib name.package name.item name, bzw. ...all).

\underline{Beispiel:} C <= not (A xor B) after FREDS LIB.MY DEFS.UNIT DELAY;

— oder nach einer use Anweisung —

         use FREDS LIB.MY DEFS.UNIT DELAY;
         C <= not (A xor B) after UNIT DELAY;

1.3.1 Package

Üblicherweise dienen Packages dazu Gruppen von Deklarationen zusammenzufassen, die in mehreren Designs benutzt werden, z.B. für Komponenten einer Bibliothek Unterprogramme (Funktionen, Prozeduren) Typen, Konstanten, Dateien…

Die Zellbibliotheken der ASIC-Hersteller werden so über spezielle Bibliotheken und Packages zur Vefügung gestellt. Auf der anderen Seite liefern die Hersteller von CAD-Software Hilfsroutinen und Funktionen, die den Umgang mit den Werkzeugen erleichtern, in Form von Packages mit.

1.3.2 Entity

Ein entity definiert für eine Komponente des Entwurfs die externe Sichtweise. Dabei werden der Name, die Ein- und Ausgänge und zusätzliche Deklarationen festgelegt. Nach der Übersetzung in eine Bibliothek kann ein entity dann als Teil anderer Entwürfe benutzt werden. Die interne Realisierung wird dann als architecture beschrieben.

\underline{Syntax:} entity entity name is [generics] [ports] [declarations (constants, ports, signals)]

[begin  normalerweise nicht benutzt

statements] end [entity name];

Das nachfolgende Beispiel zeigt die Entity-Beschreibung eines Bitvergleichers

\underline{Beispiel:} entity COMPARE is

port (  A, B: in bit;  Ein-/Ausgänge: Richtung und Datentyp

                   C: out bit);
         end COMPARE;

   [figure: COMPARE; A; B; C; bit; bit; bit]

1.3.3 Architecture

Eine Architektur beschreibt das Verhalten, bzw. die interne Realisierung einer vorher analysierten entity. Dabei können mehrere Architekturen für eine entity deklariert werden (Unterstützung von Alternativen), die Auswahl einer bestimmten architecture erfolgt dann später über eine configuration.

\underline{Syntax:} architecture architecture name of entity name is [arch declarative part]

        begin

[arch statement part] end [architecture name];

Der arch declarative part beschreibt Typen, Unterprogramme und Konstanten, die nur für diese Architektur benötigt werden, während der arch statement part das eigentliche Design beschreibt. Für diese Beschreibung gibt es drei Stile: Verhalten, Datenfluß, Struktur. Innerhalb des arch statement part kann einer oder eine beliebige Kombination dieser Stile benutzt werden.

Verhalten Das Grundkonstrukt der Verhaltensbeschreibung ist der process.

interner Aufbau: Ein VHDL-Prozeß ist einem Programm einer Programmiersprache vergleichbar, mit den üblichen Konzepten:

– sequentielle Abarbeitung der Anweisungen
– Kontrollanweisungen zur Steuerung des Ablaufs
– Verwendung lokaler Variablen, -Datentypen
– Unterprogrammtechniken (Prozeduren und Funktionen)

Aktivierung: Da das Ziel der VHDL Beschreibung ein durch den Simulator ausführbares Verhalten ist, gibt es spezielle Konstrukte, die festlegen wann der Prozeß zu aktivieren ist — im Gegensatz zu Programmen in herkömmlichen Sinne sind Hardwareelemente immer, gleichzeitig aktiv.

Ein Prozeß hat deshalb üblicherweise entweder eine sensitivity list oder enthält wait-Anweisungen. Beide Methoden bewirken, daß bei der Änderung von Eingangswerten der Architektur der Prozeß von Simulator aktiviert wird, die Anweisungen sequentiell abgearbeitet werden und dadurch neue Ausgangswerte erzeugt werden.

Ein-/Ausgabe: Nur über Signale können Prozesse nach außen hin aktiv werden. Diese Signale können zum einen Ein- und Ausgänge der Schaltung sein, zum anderen können auch mehrere Prozesse über (architektur-)interne Signale kommunizieren.

In Gegensatz zu den Signalen können die Variablen des Prozesses nur prozessintern verwendet werden und stellen so etwas wie lokalen Speicher dar.

Um Parallelitäten im Verhalten einer architecture zu beschreiben, können innerhalb des Anweisungsteils beliebig viele Prozesse beschrieben werden.

\underline{Beispiel:} architecture ARCH BEHAV of COMPARE is
    begin

process (A, B)  Prozeß, sensitiv zu Eingängen A und B

      begin
        if (A = B) then
          C <= '1' after 1 ns;
        else
          C <= '0' after 2 ns;
        end if;
      end process;
    end ARCH BEHAV;

Datenfluß Bei dieser Beschreibung wird der Datenfluß über kombinatorische logische Funktionen (Addierer, Komparatoren, Decoder, Gatter…) modelliert.

\underline{Beispiel:} architecture ARCH DATFL of COMPARE is
         begin

C <= not (A xor B) after 1 ns;  Datenfluß von Eingängen, über

         end ARCH DATFL;                                 xor und not, zum Ausgang

Struktur Strukturbeschreibungen sind Netzlisten aus Bibliothekselementen: diese Elemente werden instanziiert und über Signale miteinander verbunden.

\underline{Beispiel:} architecture ARCH STRUC of COMPARE is

signal I: bit;  lokales Signal
component  Komponentendeklaration

           XR2 port (X,Y: in bit; Z: out bit);  der Bibliothekselemente

         end component;
         component
           INV port (X: in bit; Z: out bit);
         end component;

begin  Beschreibung der Netzliste
U0: XR2 port map (A,B,I);  Benutzung der Komponenten

           U1: INV port map (I,C);
         end ARCH STRUC;

   [figure: A; B; C; Z; Z; X; X; Y; XR2; INV; U0; U1; I]

1.3.4 Configuration

Durch Konfigurationen kann der Entwerfer zwischen verschiedenen Design-Alternativen und -Versionen auswählen. Dabei bestimmt eine Konfiguration, welche Realisierung — von möglicherweise mehreren vorhandenen Architekturen — für ein Entity aus der Bibliothek, bei dessen Instanziierung benutzt wird.

\underline{Syntax:} configuration conf name of entity name is

conf specification end [conf name];

Existiert zu einem entity keine expliziten Konfiguration, so wird jeweils die (zeitlich) zuletzt analysierte Architektur benutzt — die null Konfiguration.

In dem nachfolgenden Beispiel wird das entity COMPARE in einer ALU benutzt (strukturelle Beschreibung der architecture ... of ALU).

\underline{Beispiel:} entity ALU is  Entity Beschreibung der ALU

           port ( opcode: ...
         end ALU;

architecture FIRST of ALU is  Architektur der ALU (Strukturbeschreibung)

           component COMPARE
             port (A,B: in bit; C: out bit);
           end component;
           ...
         begin

           U0: COMPARE port map (S,D,Q);  Instanz U0 des entity COMPARE

           ...
         end FIRST;
         configuration FAST ONE of ALU is

for FIRST  Architektur die konfiguriert wird

             for U0: COMPARE use entity WORK.COMPARE(ARCH BEHAV)

...  legt Entitynamen und dessen Architektur fest

           ...
         end FAST ONE;

Da Konfigurationen seperate Entwurfseinheiten sind, können sie auch direkt für die Simulation benutzt werden. In obigem Beispiel wäre es möglich diese Konfiguration zu simulieren

als: vhdlsim WORK.FAST ONE.

1.4 zeitliche Kontrolle

Bei der Einführung eines Zeitbegriffs innerhalb der Simulation, muß man unterscheiden zwischen der Art und Weise, wie Anweisungen im VHDL-Code sequentiell abgearbeitet werden und dem Verstreichen von simulierter Zeit.

Verhaltensbeschreibungen : Wie in Programmiersprachen, wird das Verhalten durch einen sequentiellen Ablauf von Anweisungen beschrieben. Die Abarbeitung dieser Anweisungen beeinflußt die simulierte Zeit nicht.

Strukturbeschreibungen : Entsprechend realen Schaltungen sind alle Strukturelemente parallel aktiv, eine Reihenfolge der entsprechenden Anweisungen im Code ist irrelevant. Die Verzögerungen der einzelnen Elemente bestimmen die simulierte Zeit.

Üblicherweise wird für die Simulation von VHDL ein ereignisgesteuerter Simulator mit zwei-Listen Technik benutzt^{1}. Eine verwaltet die vorherigen Werte der Signale, die andere Liste die neu berechneten.

Eine fiktive Zeiteinheit (delta-time) erlaubt die Behandlung von Signalzuweisungen ohne Verzögerungszeit. Dadurch kann der Simulator die Grundschleife der Simulation mehrfach durchlaufen, ohne daß die simulierte Zeit fortschreitet. Um die Wirkungsweise von Signalzuweisungen besser zu verstehen, sei hier kurz der Simulationszyklus skizziert:

1. Aktivierung des Zyklus zu einem Zeitpunkt t_{0} durch Signalzuweisungen, die für diesen Zeitpunkt im Schedule sind.

2. Durch diese Signaländerungen werden alle parallelen Anweisungen und Prozesse, die zu diesen Signalen sensitiv sind, aktiviert.

3. In einer ersten Phase werden die Signale der aktiven Prozesse ausgewertet und Ausdrücke berechnet.

4. In der zweiten Phase werden dann neue Werte an die Signale zugewiesen. Entsprechend den Verzögerungszeiten werden die Werteänderungen in die Scheduling-Tabelle übernommen.

5. Damit ist ein Durchlauf für den Zeitpunkt t_{0} abgeschlossen. Waren bei den Signalzuweisungen in Schritt 4 auch welche ohne Verzögerungszeit, so wird der Simulationszyklus beginnend bei Schritt 2 wiederholt — der Zeitschritt ist delta-time, die simulierte Zeit bleibt bei t_{0}.

1In Bezug auf Simulationsalgorithmen sei auf die entsprechenden Vorlesungen (CAD-Algorithmen…)

verwiesen

2 Datentypen

VHDL ist eine stark typisierte Sprache, d.h. Konstante, Variablen und Signale haben einen, durch deren Deklaration festgelegten Typ. Bei der Codeanalyse wird die Konsistenz der Datentypen bei Operationen und Zuweisungen überprüft. Gegebenenfalls müssen Konvertierungsfunktionen benutzt werden.

Neben den Typen des Package STANDARD, die immer bekannt sind, werden hier auch noch Typen aus den folgenden zwei Packages vorgestellt:

 std_logic_1164 in Bibliothek IEEE

textio  in Bibliothek STD

2.1 Skalare

Die einfachen Datentypen in VHDL sind denen in Standard-Programmiersprachen vergleichbar:

Character : die character Literale entsprechen dem Standard ASCII Zeichensatz, die darstellbaren Zeichen werden dabei in einfache Hochkommas eingeschlossen: '0'–

     '9', 'a'–'z', 'A'–'Z'.^{2}

Bit : die beiden logischen Werte '0' und '1' sind bit Literale.^{2}

Std Logic : der IEEE Standard 1164 ist in einem extra Package std_logic_1164 in der Library IEEE definiert. Dabei wird ein Logiksystem mit neun Signalwerten, bzw. Treiberstärken definiert, das für die Simulation und Synthese von Hardware besser geeignet ist als der Typ Bit. Die Werte sind im einzelnen:

'U' noch nicht initialisiert
'X' treibend unbekannt
'0' treibend logische 0
'1' treibend logische 1
'Z' hochohmig – für Busse mit three-state
'W' schwach unbekannt
'L' schwach logische 0
'H' schwach logische 1
'-' don’t care – für Logiksynthese

Zusammen mit diesen Datentyp, der ja auch Werte für die Modellierung von threestate Bussen beinhaltet, ist eine Auflösungsfunktion definiert, die mehrere Treiber auf einer Leitung zuläßt (siehe 6.3, Seite 36).

Boolean : die beiden boole’schen Werte true und false sind boolean Literale.

2Wegen der Typbindung in VHDL kann es notwendig sein, zur Unterscheidung der Typen deren Werte explizit zu klassifizieren: character'('1') bit'('1')

Integer : Zahlen sind möglich von −2^{31}−1 bis +2^{31}−1 (−2 147 483 647 bis +2 147 483 647). Die default-Zahlendarstellung ist dezimal; bei der Benutzung anderer Zahlenbasen wird explizit angegeben:

 binär  2#...#
 octal  8#...#

hexadecimal 16#...#

\underline{Format:} [+|-][2#|8#|16#]number[#]

Meist sind zu integer noch Untertypen definiert, wie:

 POSITIVE : 1. . . n
 NATURAL : 0. . . n

Real : Zahlen sind möglich von −1.0e + 38 bis +1.0e + 38, die default-Zahlendarstellung ist dezimal.

\underline{Format:} [+|-][2#|8#|16#]number.number[#][e[+|-]number]

Physikalische Literale : zusätzlich zu den eigentlichen Wertangaben erlaubt VHDL noch die Angabe physikalischer Maßeinheiten. In dem package STANDARD sind als Typ TIME folgende Maßeinheiten definiert: fs, ps, ns, us, ms, sec, min, hr. Dadurch können Verzögerungszeiten modelliert werden: C <= ... after 2 ns;

Aufzählungstypen : um die Aufgabenstellung unabhängig von speziellen technischen Codierungen beschreiben zu können, kann der Benutzer beliebige Aufzählungstypen definieren.^{3}

\underline{Syntax:} type enum name is (enum liter \{, enum liter\});

Dabei können für enum liter beliebige Bezeichner (erstes Beispiel) aber auch Literale (character Literale im zweiten Beispiel) benutzt werden.

\underline{Beispiel:} type AMPEL is (ROT, GELB, GRUEN);  für Ampelsteuerung
         type FOURVAL is ('X', '0', '1', 'Z'); vierwertige Logik für Simulation

Untertypen : zu vordefinierten, bzw. zu eigenen Typen lassen sich Untertypen bilden, dies geschieht üblicherweise durch Einschränkung der Wertebereiche. Solche Bereichseinschränkungen lassen sich zwar auch bei der Variablen- und Signaldeklaration angeben, Untertypen bieten aber den Vorteil, daß solche Begrenzungen zentral vorgenommen werden können.

3Die Typen character, bit und boolean sind im package STANDARD als Aufzählungstypen vordefiniert.

\underline{Beispiel:} subtype DIGIT is integer range 0 to 9;  Untertyp zu integer

    ...
    variable MSD, LSD: DIGIT;

— ist äquivalent zu —

    variable MSD, LSD: integer range 0 to 9;

2.2 komplexe Typen

Array : Wie in Programmiersprachen bestehen Arrays aus durchnumerierten Elementen gleichen Typs. Dabei sind in entsprechenden Packages schon folgende Array-Typen vordefiniert:

String : Array Typ zu character — in Package STANDARD

type STRING is array (POSITIVE range <>) of CHARACTER;

Bit Vector : Array Typ zu bit — in Package STANDARD

type BIT VECTOR is array (NATURAL range <>) of BIT;

Std Logic Vector : Array Typ zu std_logic — in Package STD_LOGIC_1164

type STD LOGIC VECTOR is array ( NATURAL range <>) of STD LOGIC;

Da die Hersteller für diesen Datentyp auch gleich logische und arithmetische Operatoren anbieten, kann es notwendig sein die Zahlendarstellung genau zu spezifizieren, um beispielsweise zwischen unsigned und signed Darstellung zu unterscheiden (siehe 4, Seite 23). Gegebenenfals muß die Zahlendarstellung über die Bindung an Untertypen explizit dargestellt werden. In dem Package STD_LOGIC_ARITH sind deshalb definiert:

 type UNSIGNED is array (NATURAL range <>) of STD LOGIC;
 type SIGNED is array (NATURAL range <>) of STD LOGIC;

Die Deklaration eigener Array Typen besteht dabei aus der Angabe des Arraytyp-Namens, der Beschreibung des Index (der Indices bei mehrdimensionalen Arrays) durch Index-Typ(en) und Index-Bereich(e) und der Angabe des Element-Typs.

\underline{Syntax:} type array name is array (index description) of element type;

Möglichkeiten für index description

index range |  integer Bereich
index type |  Aufzählungstyp als Index
index type range index range |  allg. Typ-Bereich
index type range <>  unbegrenzter Typ; Bereichsangabe bei Var-Dekl.

Nachfolgend werden einige Eigenschaften von Arrays anhand von Beispielen genauer erläutert.

Index-Typen : neben den üblichen Integer-Indices können auch eigene Aufzählungstypen (-untertypen) benutzt werden.

\underline{Beispiel:} type INSTRUCTION is (ADD, SUB, LDA, LDB, STA, STB, OUTA);
subtype FLAGS is integer range (0 to 7);
...
type INSTR FLAG is array (INSTRUCTION) of FLAGS;

Array von Flag-Werten

Benutzung als Laufindex : Indices können innerhalb von Schleifen über Variablen incrementiert/decrementiert werden.

\underline{Beispiel:} ...

process ...
  variable INFO : bit vector (0 to 49);
  variable START : integer;
  variable OUTBYTE : bit vector (0 to 7);
begin
  for I in 0 to 7 loop
    OUTBYTE(I) := INFO(I + START);
  end loop;
end process;

Unbegrenzte Indices : oft werden Indices über den gesamten Wertebereich des Aufzählungstypen deklariert und dann später bei der Variablendeklaration werden erste Bereichseinschränkungen vorgenommen.

\underline{Beispiel:} type BIT VECTOR is array (NATURAL range <>) of BIT;

...  Deklaration aus STANDARD

variable BYTE: BIT VECTOR (0 to 7);

Index-Bereiche : vergleichbar den Wertebereichseinschränkungen von Variablen ist die Reihenfolge des Index wichtig.

\underline{Beispiel:} type AVEC is array (0 to 3) of bit;
type BVEC is array (3 downto 0) of bit;
...
variable AV: AVEC;
variable BV: BVEC;
...

AV := "0101";  ⇒ AV(0)='0' AV(1)='1' AV(2)='0' AV(3)='1'
BV := "0101";  ⇒ BV(0)='1' BV(1)='0' BV(2)='1' BV(3)='0'

Array-Zuweisungen : können entweder über die Position, den Namen oder gemischt erfolgen.

\underline{Syntax bei Namen:} [typ name']  optionale Typ-Qualifizierung

( selector => expression{, selector => expression}[, others => expression] )

\underline{Beispiel:} variable C: BIT VECTOR (0 to 3);
variable H, I, J, K: bit;

mögliche Zuweisungen

C := "1010";  4-bit string
C := H & I & J & K;  Konkatenation

C := ('1', '0', '1', '0');  Aggregat

Aggregatzuweisungen

C := ('1', I, '0', J or K);  Position
C := (0 => '1', 3 => J or K, 1 => I, 2 => '0');  Name
C := ('1', I, others => '0');  gemischt

Auschnitte : können über die Indizes gebildet werden.

\underline{Beispiel:} variable A: BIT VECTOR (3 downto 0);
variable B: BIT VECTOR (8 downto 1);
...

B(6 downto 3) := A;  4 bit Slice von A

Mehrdimensionale Arrays : können über mehrere Indices erzeugt werden.

\underline{Beispiel:} type MEMORY is array (0 to 7, 0 to 3) of bit;  8 × 4 bit Array

...
constant ROM: MEMORY := ( ('0','0','0','0'),
                          ('0','0','0','1'),
                          ('0','0','1','0'),
                          ('0','0','1','1'),
                          ('0','1','0','0'),
                          ('0','1','0','1'),
                          ('0','1','1','0'),
                          ('0','1','1','1'));
variable DATA BIT: bit;
...

DATA BIT := ROM (5,3);  ist '1'

Es lassen sich auch Arrays von Arrays bilden; die Indices werden hierbei getrennt behandelt.

\underline{Beispiel:} type WORD is array (0 to 3) of bit;  4 bit Zeile
type MEMORY is array (0 to 7) of WORD;  8 × 4 bit Array

...
constant ROM: MEMORY := ( ('0','0','0','0'),
                          ('0','0','0','1'),
                          ...
                          ('0','1','1','1'));
variable DATA: WORD;
variable DATA BIT: bit;
variable ADDR, INDEX: integer;
...
DATA := ROM (ADDR);
DATA BIT := ROM (ADDR)(INDEX);

Array Untertypen : lassen sich zu bestehenden Arrays, bzw. zu unbegrenzten Arrays definieren.

\underline{Beispiel:} subtype BYTE is BIT VECTOR (7 downto 0);  unbegrenzter Typ

                                                    BIT VECTOR

Record : Elemente verschiedener Typen (Skalare oder zusammengesetzte Typen) können mit Hilfe von Records zusammengefaßt werden, um abstrakte Datenmodelle zu bilden. Die einzelnen Felder des Records werden über die Namen dereferenziert.

\underline{Beispiel:} type TWO DIGIT is  Zahlen von −99 bis +99

record  SIGN  : bit;
      MSD   : integer range 0 to 9;
      LSD   : integer range 0 to 9;
end record;
...
process ...
variable ACNTR, BCNTR: TWO DIGIT;
begin

ACNTR.SIGN := '1';  Zugriff auf Felder

ACNTR.MSD := 1;
ACNTR.LSD := ACNTR.MSD;
...

BCNTR := TWO DIGIT'('0',3,6);  Aggregat, Typ-qualifiziert

...
end process;

Alias Deklarationen : Eine zweite Möglichkeit, neben Records, auf Teilstrukturen über Namen zuzugreifen, bieten Alias-Namen. So lassen sich beispielsweise Teile von Arrays über solche selbstdefinierten Namen selektieren.

Nachfolgend wird der im vorigen Beispiel benutzte Record-Typ TWO DIGIT mit Hilfe von alias Anweisungen nachgebildet.

\underline{Beispiel:} signal ACNT: bit vector(1 to 9);  vergl. voriges Beispiel

alias SIGN: bit is count(1);
alias MSD:  bit vector(1 to 4) is count(2 to 5);
alias LSD:  bit vector(1 to 4) is count(6 to 9);
...

SIGN  := '1';  Benutzung

MSD   := "1001";
LSD   := MSD;
...
COUNT := "110011001";

Text I/O : In dem package TEXTIO sind die Datentypen text und line deklariert, sowie Funktionen die den (aus Programmiersprachen gewohnten) Zugriff auf Textdateien erlauben; so ist es beispielsweise möglich Testvektoren aus einer Datei einzulesen und in der Simulation zu benutzen.

\underline{Beispiel:} use std.textio.all;  Standardbeispiel: Datei1 lesen, in Datei2 schreiben

entity COPY4 is                              entity ohne Anschlüsse

end COPY4;
architecture FIRST of COPY4 is
begin
  process (go)

    file INSTUFF: text is in "\path\test.data";  Eingabedatei
    file OUTFILE: text is in "\path\out.data";  Ausgabedatei

    variable L1, L2 line;
    variable VECT: bit vector(3 downto 0);
    begin

      while not (endfile(INSTUFF)) loop  bis zum Dateiende
        readline (INSTUFF, L1);  liest Zeile aus Datei

read (L1, VECT);  liest Vektor aus Zeile
write (L2, VECT);  schreibt Vektor in Zeile

        writeline (OUTFILE, L2);  schreibt Zeile in Datei

      end loop;
    end process;
end FIRST;

In dem package TEXTIO sind unter anderem vordefiniert:

Typen:  LINE, TEXT

Standarddateien: INPUT, OUTPUT

Prozeduren:  READ, READLINE, WRITE, WRITELINE
Funktionen:  ENDLINE, ENDFILE

Zugriffstypen : Wie Zeiger in Programmiersprachen können Zugriffstypen dazu benutzt werden dynamisch Speicherstrukturen zu alloziieren. Variablen vom Typ access sind Zeiger auf skalare oder komplexe Datenstrukturen.

\underline{Syntax:} type ptr type name is access type name;

Für die Arbeit mit Zugriffstypen sind zwei Operatoren definiert.

New : wird bei Zuweisungen an eine Variable des Zugriffstyps als Keywort benutzt. Dabei sind Initialisierungen möglich. Wenn der Zeiger auf einen unbeschränkten Typ zeigt, sind Bereichseinschränkungen notwendig, wie z.B. bei string.

Deallocate : um Speicherbereiche wieder freizugeben steht eine Prozedur zur Verfügung, die als Parameter die Variable des Zugriffstyps übergeben bekommt.

\underline{Beispiel:} type CELL;  unvollständige Typdeklaration

type LINK is access CELL;  Zugriffstyp

type CELL is  genaue Typdeklaration

  record
    VALUE : integer;
    NEXTP : LINK;
  end;

variable HEAD, TEMP : LINK;  Zeiger auf CELL

...

TEMP := new CELL'(0, null);  neues Element, mit Initialisierung

for I in 1 to 5 loop

HEAD := new CELL;  weitere Elemente

  HEAD.VALUE := I;  Zugriff auf record

  HEAD.NEXTP := TEMP;
  TEMP := HEAD;
end loop;
...

deallocate(TEMP);  Speicherfreigabe

Speicheranforderung

new CELL;  neues Element
new CELL'(I, TEMP);  … mit Initialisierung

… mit notwendiger Bereichsbeschränkung

new BIT VECTOR (15 downto 0);  durch Index
new BIT VECTOR'("001101110");  durch Initialisierung

2.3 Attribute

Symbolische Attribute in VHDL erlauben allgemeineren Code zu schreiben, da Konstanten oder Literale nicht an mehreren Stellen stehen müssen, sondern über Attributierungsmechanismen zum Zeitpunkt der Übersetzung ermittelt werden.

Dimensionierung : Die Attribute ermitteln für Array- und Aufzählungstypen, beziehungsweise Variablen und Signale dieser Typen, Bereichsgrenzen und Längen. Bei mehrdimensionalen Arrays wird die Ordnungsnummer des Index mit angegeben.

\underline{Syntax:} Bereichsgrenzen ...'left[(n)] linke Grenze (Index n) ...'right[(n)] rechte Grenze (Index n) ...'high[(n)] Obergrenze (Index n) ...'low[(n)] Untergrenze (Index n)

Arraylängen ...'length[(n)] Anzahl der Elemente (Index n)

Bereiche

...'range[(n)]  Bereich ..to/downto.. (Index n)
...'reverse range[(n)] Bereich ..downto/to.. (Index n)

\underline{Beispiel:} Bereichsgrenzen

type T RAM DAT is array (0 to 511) of integer;
variable RAM DAT: T RAM DAT;
...
for I in RAM DAT'low to RAM DAT'high loop
  ...

Bereichsgrenzen mehrdimensional

variable MEM (0 to 15, 7 downto 0) of MEM DAT;
...
MEM'left(1)  ist 0
MEM'right(1)  ist 15
MEM'left(2)  ist 7
MEM'right(2)  ist 0
MEM'low(2)  ist 0
MEM'high(2)  ist 7

Arraylängen

type BIT4 is array (0 to 3) of BIT;
type BIT STRANGE is array (10 to 30) of BIT;
...
BIT4'length  ist 4
BIT STRANGE'length  ist 21

Bereiche

function VEC2INT (INVEC: bit vector) return integer is
  ...
begin
  for I in INVEC'range loop
    ...

Ordnung : Die Attribute ermitteln für Aufzählungstypen Werte, Ordnungszahlen und übergeordnete Typen (bei Untertypen).

\underline{Syntax:} Wertermittlung type'succ(value) Wert nach value type'pred(value) Wert vor value type'leftof(value) Wert links von value type'rightof(value) Wert rechts von value

Ordnung type'pos(value) Position von value type'val(position) Wert von position

übergeordnete Typen type'base Basistyp zu subtype type

\underline{Beispiel:} type COLOR is (RED, BLUE, GREEN, YELLOW, BROWN, BLACK);
subtype TLCOL is COLOR range RED to GREEN;
...
COLOR'low  ist RED
COLOR'succ(RED)  ist BLUE
TLCOL'base'right  ist BLACK
COLOR'base'left  ist RED
TLCOL'base'succ(GREEN) ist YELLOW

3 Bezeichner und Deklarationen

Identifier dienen dazu Objekte zu benennen. Mit Ausnahme einiger reservierter Wörter kann der Benutzer beliebige Namen vergeben, dabei gilt:

1. Zeichensatz 'a'… 'z', '0'… '9', ' '.
2. das erste Zeichen muß ein Buchstabe sein.
3. keine Unterscheidung zwischen Groß- und Kleinschreibung in VHDL

Bei Verwendung von Bibliotheken und Packages müssen die Elemente gegebenenfalls über komplette Namen derefenziert werden, wie: lib name.package name.item name

Kommentare : beginnen mit zwei -- Zeichen und gehen bis zum Ende der Zeile.

Konstanten : legen einmalig Werte innerhalb eines package, einer entity oder einer

     architecture fest.

\underline{Syntax:} constant identifier: type [range expr][:= expression];

     \underline{Beispiel:} constant Vcc:   real       := 4.5;
              constant CYCLE: time       := 100 ns;
              constant PI:    real       := 3.147592;
              constant FIVE:  bit vector := "0101";

Variablen : speichern Werte innerhalb eines process und werden dort, durch den Kontrollfluß gesteuert, sequentiell benutzt. Variablen können nicht benutzt werden, um Informationen zwischen Prozessen auszutauschen.

\underline{Syntax:} variable identifier list: type [range expr][:= expression];

Bei der Deklaration können die Wertebereiche der Variablen eingeschränkt werden und die Initialisierung mit Werten ist möglich.

     \underline{Beispiel:} variable INDEX:      integer range 1 to 50 := 10;
              variable CYCLE TIME: time range 10 ns to 50 ns := 10 ns;
              variable REGISTER:   std logic vector (7 downto 0);
              variable X, Y:       integer;

Signale : verbinden Design-Entities untereinander und übertragen Wertewechsel innerhalb der Schaltung. Die Kommunikation zwischen Prozessen findet über Signale statt.^{4}

\underline{Syntax:} signal identifier list: type [range expr][:= expression];

4Wegen der besonderen Bedeutung von Signalen in VHDL wird auf sie später noch genauer eingegangen in Abschnitt 6.

Bei der Deklaration können die Wertebereiche der Signale eingeschränkt werden und die Initialisierung mit Werten ist möglich.

\underline{Beispiel:} signal COUNT:     integer range 1 to 50;
         signal GROUND:    bit := '0';
         signal INT BUS:   std logic vector (1 to 8);

\underline{Achtung:} Signale können nicht innerhalb eines Prozesses deklariert werden. Sie können zwar innerhalb des process benutzt werden, aber Signalzuweisungen werden in der Simulationszeit abgearbeitet. Das heißt, daß Signalzuweisungen nicht in der sequentiellen Reihenfolge im Prozess wirksam werden, sondern erst, wenn der Prozess ein wait-Statement erreicht.

Um den zeitlichen Charakter der Signalzuweisung hervorzuheben, wird auch ein anderer Zuweisungsoperator als bei Variablen benutzt, für den Ablauf der Simulationszeit können außerdem Verzögerungen bei der Signalzuweisung modelliert werden:

 signal xyz: bit;
 ...
 xyz <= '1' after 5 ns;

Die Benutzung von Signalen im sequentiellen Fluß des Prozesses führt daher oft zu (unerwartet) fehlerhaften Ergebnissen. Deshalb empfiehlt es sich im sequentiellen Ablauf eines VHDL-Prozesses (mit Schreib- und Leseoperationen) mit Variablen zu arbeiten und den berechneten Wert dann vor dem nächsten wait an Signale weiterzugeben.

Abschließend noch zwei Anmerkungen zum Umgang mit Variablen und Signalen:

Initialisierung : werden Variable oder Signale bei der Deklaration nicht explizit initialisert, so werden sie bei der Simulation folgendermaßen vorbesetzt:

Aufzählungstypen : der erste Wert der Aufzählungsliste
integer, real : der niedrigste darstellbare Wert

Dies wird gerade bei den Aufzählungstypen oft ausgenutzt, beispielsweise indem man den Startzustand eines endlichen Automaten als ersten definiert oder bei dem Typ std_logic wo mit 'U' (nicht initialisiert) begonnen wird.

Bereichseinschränkung : um Variable oder Signale für die Hardwaresynthese zu benutzen, sollte entsprechend der geplanten Bitbreite eine Bereichseinschränkung vorgenommen werden — dies ist gerade bei integer-Typen notwendig, da sonst 32-bit Datenpfade generiert werden.

\underline{Beispiel:} signal CNT100:    integer range 0 to 99;  unsigned 7-bit
         signal ADDR BUS:  std logic vector (7 to 0);  8-bit

4 Ausdrücke

Um Ausdrücke zu bilden, hat man in VHDL die in der Tabelle aufgeführten Operatoren zur Verfügung, die Operatorprioritäten steigen an. Gegebenenfalls muß die Reihenfolge der Auswertung durch explizite Klammerung festgelegt werden:

Operator Funktion  Operanden Typ1 - Typ2

logische Operatoren

and  a ∧ b  bit, bit vector, boolean - =
or  a ∨ b  bit, bit vector, boolean - =
nand  ¬(a ∧ b)  bit, bit vector, boolean - =
nor  ¬(a ∨ b)  bit, bit vector, boolean - =
xor  a ≠ b  bit, bit vector, boolean - =

relationale Operatoren

=  a = b  gleicher Typ
/=  a ≠ b  gleicher Typ
<  a < b  gleicher Typ
<=  a ≤ b  gleicher Typ
>  a > b  gleicher Typ
>=  a ≥ b  gleicher Typ

arithmetische Operatoren - additiv

+  a + b  integer, real - =
-  a − b  integer, real - =
&  a&b  bit, bit vector, character, string - passend

arithmetische Operatoren - vorzeichen

+  +a  integer, real
-  −a  integer, real

arithmetische Operatoren - multiplikativ

*  a ∗ b  integer, real - =
/  a/b  integer, real - =
mod  a div b  integer - =
rem  a mod b  integer - =

weitere Operatoren

**  a^{b}  integer, real - integer
abs  | a |  integer, real
not  ¬a  bit, bit vector, boolean

Da VHDL streng typisiert ist, müssen zum Teil explizite Angaben des Typs, sowie Typkonvertierungen vorgenommen werden.

Qualifizierungen : erlauben die explizite Angabe eines Typs, dies ist beispielsweise notwendig, wenn keine eindeutige Zuordnung möglich ist.

\underline{Syntax:} type'(expression)

\underline{Beispiel:} type MONTH is (APRIL, MAY, JUNE);
type NAMES is (APRIL, JUNE, JUDY);

... MONTH'(JUNE) ...  für Monat
... NAMES'(JUNE) ...  für Namen

Konvertierungen : sind auf Grund der Typbindungen teilweise notwendig. Für die Standardtypen sind Konvertierungsfunktionen vordefiniert, bei eigenen Typen müssen sie bei Bedarf durch den Benutzer angegeben werden.^{5}

\underline{Beispiel:} type FOURVAL is ('X', 'L,', 'H', 'Z');  vierwertige Logik, die erste

type VALUE4 is  ('X', '0,', '1', 'Z');  . . . , die zweite

...
function CONVERT4VAL (S: FOURVAL) return VALUE4 is

begin  Konvertierungsfunktion

  case S is
    when 'X' => return 'X';
    when 'L' => return '0';
    when 'H' => return '1';
    when 'Z' => return 'Z';
  end case;
end COVERT4VAL;
...

process (ABC)  … benutzt die Konvertierungsfunktion

  variable ABC: FOURVAL;
  variable XYZ: VALUE4;
...
  XYZ := CONVERT4VAL (ABC);
...

5Funktionen sind in Abschnitt 5.2, Seite 29 beschrieben.

IEEE 1164 – Std Logic Vector Für den Datentyp std_logic, bzw. std_logic_vector, sind in extra Packages Operatoren auf diesen Typen definiert. Um dabei zwischen unsigned und signed (2-Komplement) Zahlendarstelungen zu unterscheiden – speziell für die Auswertung der Vergleichsoperatoren ist dies wichtig –, werden zwei Packages in der Bibliothek IEEE definiert, sie enthalten:

 std logic 1164

   logisch  and nand or nor xnor not

 std logic unsigned / std logic signed

relational  = /= < <= > >=
arithmetisch + -, + - abs, *

Ausserdem befinden sich in diesen Packages noch weitere Operatoren für das shiften von Vektoren, sowie Konvertierungsfunktionen.

\underline{Beispiel:} library IEEE;  Bibliothek benutzen

         use IEEE.STD LOGIC 1164.ALL;  Packages benutzen

         use IEEE.STD LOGIC SIGNED.ALL;
         ...

           VARA := "1011";                                                  = -5
           VARB := "0011";                                                   = 3
           if (VARA > VARB) then                                           false

           ...

Ist die Zuordnung au einer Zahlendarstellung nicht eindeutig möglich, wie beispielsweise bei Literalen, so können die Subtypen (unsigned, signed) explizit angegeben werden.

\underline{Beispiel:} signed'("1011") > signed'("0011")                                 false

5 Sequentielle Beschreibungen

Die zentrale Rolle bei sequentiellen Beschreibungen spielt der Prozeß. Das process-State-ment wird für die Verhaltensbeschreibung von Architekturen benutzt, und begrenzt einen Bereich, in dem Anweisungen sequentiell abgearbeitet werden.

Das process-Statement selber ist eine konkurrente Anweisung, d.h. es können beliebig viele Prozesse gleichzeitig aktiv sein, ihre Reihenfolge im VHDL-Code ist irrelevant.^{6}

\underline{Syntax:} [proc label:] process [(sensitivity list)] [subprogram decl|subprogram body] [type decl] [subtype decl] [constant decl] [variable decl] [file decl] [alias decl] [attribute decl] [attribute spec] [use clause]

        begin

[sequential statements]

        end process [proc label];

Hier noch eine Anmerkung: das optionale Label (proc label) ist bei der Simulation für das Debugging der Schaltung nützlich und sollte deshalb vergeben werden.

Das Beispiel simuliert die Auswahl des Minimums und Maximums aus drei Eingangswerten mit Hilfe von zwei Prozessen.

\underline{Beispiel:} entity LOW HIGH is

           port (  A, B, C: in integer;  Eingänge
                   MI, MA: out integer);  Ausgänge

         end LOW HIGH;
         architecture BEHAV of LOW HIGH is
         begin

L: process  Auswahl des Minimum

             variable LOW: integer := 0;
             begin
               wait on A, B, C;
               if A < B    then LOW := A;
                           else LOW := B;
               end if;
               if C < LOW  then LOW := C;
               end if;

6Weitere Erläuterungen zu der process-Anweisung und deren Abarbeitung in der Simulation finden sich in Abschnitt 7, Seite 41.

          MI <= LOW after 1 ns;
        end process;

H: process  Auswahl des Maximum

        variable HIGH: integer := 0;
        begin
          wait on A, B, C;
          if A > B    then HIGH := A;
                      else HIGH := B;
          end if;
          if C > HIGH then HIGH := C;
          end if;
          MA <= HIGH after 1 ns;
        end process;
    end BEHAV;

5.1 Anweisungen

Signalzuweisung : Die Signalzuweisung innerhalb von Prozessen wird in dem extra Abschnitt 6.2, Seite 35 behandelt, da sie zwar in der sequentiellen folge eines Prozesses steht, aber bei der Simulationsabarbeitung anders behandelt wird.

Variablenzuweisung : Bei der Zuweisung müssen die Typen zusammenpassen, gegebenenfalls müssen Attributierungen oden Konvertierungsfunktionen benutzt werden.

\underline{Syntax:} variable := expression;

If : Verzweigung wie in Programmiersprachen; einfache Decodierung bei Hardwareumsetzung.

\underline{Syntax:} if condition then

sequential statements {elsif condition then sequential statements}

        [else

sequential statements]

        end if;

Case : mehrfach-Verzweigung wie in Programmiersprachen; Decodierung komplexer Codes (z.B. auf Bussen) bei Hardwareumsetzung.

\underline{Syntax:} case expression is

{when choices => sequential statements}

        end case;

Möglichkeiten für choices

value => sequential statements  genau ein Wert
value1 | value2 ... => sequential statements  Aufzählung von Werten
value1 to value2 => sequential statements  Wertebereich
others => sequential statements  Voreinstellung

Für expression müssen alle möglichen Werte aufgezählt werden oder die Anweisung muß whenothers als letzte Auswahl enthalten.

\underline{Beispiel:} case BCD is  Decoder: BCD zu 7-Segment

when "0000" => LED := "1111110";
when "0001" => LED := "1100000";
when "0010" => LED := "1011011";
when "0011" => LED := "1110011";
when "0100" => LED := "1100101";
when "0101" => LED := "0110111";
when "0110" => LED := "0111111";
when "0111" => LED := "1100010";
when "1000" => LED := "1111111";
when "1001" => LED := "1110111";

when others => LED := "-------";    don't care aus std logic 1164

end case;

Loop : Modellierung verschiedener Schleifen, entsprechend in Programmiersprachen; Wiederholung von Elementen (z.B. entsprechend der bit-Breite) bei Hardwareumsetzung.

\underline{Syntax:} [loop label:] while condition loop |  mit Abfrage
[loop label:] for identifier in value1 to value2 loop |  mit Zähler
[loop label:] loop  beliebig oft…

sequential statements end loop [loop label];

Die Laufvariable der for-Schleife muß nicht extra deklariert werden; identifier gilt als lokale Variable in der Schleife, Zuweisungen sowie externer Zugriff sind nicht möglich.

Next : bewirkt den vorzeitigen Abbruch eines Schleifendurchlaufs, die zusätzliche Angabe einer Bedingung ist möglich.

\underline{Syntax:} next [loop label][when condition];

\underline{Beispiel:} for I in 0 to MAX LIM loop

if (DONE(I) = true) then next;  Sprung zu end loop

end if;
Q(I) <= A(I);
end loop;

L1: while J < 10 loop  äußere Schleife
L2: while K < 20 loop  innere Schleife

  ...

next L1 when J = K;  Sprung aus innerer Schleife

  ...
end loop L2;

end loop L1;  Sprungziel

Exit : beendet die Ausführung einer Schleife, die zusätzliche Angabe einer Bedingung ist möglich.

\underline{Syntax:} exit [loop label][when condition];

\underline{Beispiel:} for I in 0 to MAX LIM loop

if (Q(I) <= 0) then exit;  Sprung aus Schleife

end if;
Q(I) <= (A * I);
end loop;

...  Sprungziel

Assert : ermöglicht die Überprüfung von Bedingungen zur Laufzeit des VHDL-Simulators. Dies ist bespielsweise sinvoll um Zeitbedigungen zu gewährleisten (set-up, hold …), um Bereichsgrenzen zu prüfen u.s.w.

\underline{Syntax:} assert condition [report string expr]

[severity failure|error|warning|note];

Wenn condition nicht erfüllt ist, wird als Meldung string expr ausgegeben.

\underline{Beispiel:} process (CLK, DIN)  Verhaltensmodell eines D-FF

variable X: integer;
...
begin
...
assert (X > 3)
  report "setup violation"
  severity warning;
...
end process;

Wait : kontrolliert dynamisch die Ausführung/Unterprechung des Prozesses. Dadurch können in dem Verhaltensmodell — das der Prozess letztendlich darstellt — signalabhängige Aktivitäten modelliert werden. Außerdem werden erst durch ein wait neu berechnete Werte von Signalen in der Schaltung wirksam^{7}.

\underline{Syntax:} wait [on signal name {, signal name}] [until condition] [for time expr];

Die sensitivity list eines process entspricht einem waiton... am Ende des Prozesses. Es gibt vier Grundformen der wait-Anweisung:

– wait on A, B; : Unterbrechen des Prozesses, bis ein Ereignis geschieht — hier: ein Wertewechsel auf einem der Signale A oder B.

– wait until X > 10; : Unterbrechen des Prozesses, bis eine Bedingung erfüllt ist — hier: das Signal X einen Wert > 10 hat.

– wait for 10 ns; : Unterbrechen des Prozesses, bis eine Zeitspanne verstrichen ist — hier: 10 ns simulierter Zeit.

– wait; : Unendlich langes Warten… Da ein VHDL-process immer aktiv ist, bietet diese Anweisung am Ende des Prozesses die einzige Möglichkeit ihn quasi anzuhalten — dies wird beispielsweise bei Initialisierungsprozessen benutzt, die nur einmal abgearbeitet werden sollen.

In dem Beispiel wird eine Architektur modelliert, die über zwei Prozesse eine Erzeuger/Verbraucher Situation simuliert. Über ein einfaches Handshake-Protokoll (zwei Leitungen, mit je zwei aktiven Zuständen) werden die Prozesse synchronisiert.

\underline{Beispiel:} entity PRO CON is
           ...
         end PRO CON;
         architecture BEHAV of PRO CON is

           signal PROD: boolean := false;  item erzeugt Semaphor
           signal CONS: boolean := true;  item verbraucht Semaphor

         begin

           PRODUCER: process  Erzeuger

             begin
               PROD <= false;
               wait until CONS;

... produce item

               PROD <= true;
               wait until not CONS;
             end process;

7In den Abschnitten 6.2 und 1.4 (Seiten 36,7) wird die Wirkungsweise des wait genauer erklärt.

                CONSUMER: process  Verbraucher

                  begin
                    CONS <= true;
                    wait until PROD;
                    CONS <= false;

... consume item

                    wait until not PROD;
                  end process;
              end BEHAV;

5.2 Unterprogramme

An Unterprogrammen stehen in VHDL Prozeduren (mehrere Return-Werte via Parameter) und Funktionen (gibt einen Wert zurück) zur Verfügung. Funktionen werden beispielsweise zur Typkonvertierung oder als Auflösungsfunktion (siehe Abschnitt 6.3, Seite 36) benutzt.

In Unterprogrammen können zwar lokale Variablen deklariert werden, deren Werte sind aber nur bis zum Verlassen des Unterprogramms definiert — im Gegensatz zu Variablen im process, die einem lokalen Speicher entsprechen.

Die Deklaration von Unterprogrammen muß vor deren Aufruf erfolgt sein, das heißt bei Aufruf in einem process: innerhalb der entsprechenden architecture, des entity oder

eines package.

Die Übergabe der Parameter kann beim Aufruf entweder über die Position oder über den Namen erfolgen, bei der Angabe des Namens gilt: declaration name => actual parameter

Function : hat mehrere Parameter und gibt genau einen Wert zurück — entspricht damit einem Ausdruck.

\underline{Syntax:} function func name (parameter list)

             return type name is

[variable declaration] [constant declaration] [type declaration] [use clause]

             begin

[sequential statements] return expression; [sequential statements]

end [func name];

In dem folgenden Beispiel wird ein Bitvektor in eine Integer Zahl umgerechnet.

\underline{Beispiel:} architecture ...
...

function VEC2INT (S: bit vector range 1 to 8)  Deklaration

return integer is

  variable RES: integer := 0;  lokale Variable

begin
  for I in 1 to 8 loop
    RES := RES * 2;
    if S(I) = '1'  then RES := RES + 1;
    end if;
  end loop;
  return RES;
end VEC2INT;
...
begin
...
process ...
  ...

  XVAL := VEC2INT (XBUS);  Aufruf

  ...
end process;
...
end ...

Procedure : hat mehrere Parameter, die folgende Modi haben können:

in : nur Eingangswert

out : nur Ausgangswert, d.h. die Benutzung ist nur auf die linke Seite von Zuwei-

sungen beschränkt.

inout : Ein-/Ausgangswert, kann innerhalb der Prozedur universell benutzt werden.

Für die Parameter sind außer Variablen auch Signale (nach expliziter Deklaration) zulässig. Im Code werden Prozeduren wie Anweisungen behandelt.

\underline{Syntax:} procedure proc name (parameter list) is [variable declaration] [constant declaration] [type declaration] [use clause]

begin

sequential statements end [proc name]; parameter list:

[variable] name list [in|out|inout] type name [:= expression]; | signal name list [in|out|inout] type name;

Die Prozedur des Beispiels dient, wie die Funktion oben, der Umrechnung eines Bitvektors in eine Integer-Zahl wobei zusätzlich ein Flag gesetzt wird.

     \underline{Beispiel:} architecture ...
                ...

                procedure VEC2INT  Deklaration

                  ( S: in bit vector;
                    ZFLAG: out boolean;

                    Q: inout integer ) is  wegen Zuweisung

                begin
                  Q := 0;
                  ZFLAG := true;
                  for I in 1 to 8 loop

Q := Q * 2;                                 Q auf rechter Seite

                    if S(I) = '1' then

                      Q := Q + 1;  ⇒ Modus ist: inout

                      ZFLAG := false;
                    end if;
                  end loop;
                end VEC2INT;
              begin
                ...
                process ...
                  ...

                  VEC2INT (XBUS, XFLG, XVAL);  Aufruf

                  ...
                end process;
                ...
              end ...

Overloading Wie in einigen Programmiersprachen gibt es auch in VHDL Overloading Mechanismen für Funktionen und Prozeduren. Overloading bezeichnet dabei, daß Unterprogramme mehrfach definiert sind, aber unterschiedliche Typen, beziehungsweise unterschiedlich viele Parameter haben. Bei Aufruf dieser Unterprogramme wird dann, entsprechend Anzahl und Typ der Argumente, die entsprechende Funktion/Prozedur ausgewählt. Dadurch können, trotz starker Typfestlegung, Operatoren und Funktionen allgemein benutzt werden.

Argument-Typ : zwischen den Unterprogrammen wird durch den Typ der Argumente unterschieden.

     \underline{Beispiel:} function DECR (X: integer) return integer is      integer Argument

              begin
                ...
              end DECR;

              function DECR (X: real) return real is               real Argument

              begin
                ...
              end DECR;
              ...
              variable A, B: integer;
              ...

B := DECR(A);  benutzt erste Funktion

Argument-Anzahl : zwischen der Unterprogrammen wird durch die Anzahl der Argumente unterschieden.

     \underline{Beispiel:} function CONV ADDR (A0, A1: bit) return integer is

begin  2 Argumente

                ...
              end;
              function CONV ADDR (A0, A1, A2: bit) return integer is

begin  3 Argumente

                ...
              end;
              function CONV ADDR (A0, A1, A2, A3: bit) return integer is

begin  4 Argumente

                ...
              end;

Mit Overloading lassen sich auch die bestehenden Operatoren, aus dem Default-Package STANDARD, erweitern. Gerade bei herstellerspezifischen Packages werden diese Möglichkeiten in VHDL genutzt. Eine der häufigsten Ergänzungen sind Packages die mehrwertige Logik implementieren (STD LOGIC 1164, MVL7, MVL9… – sie enthalten neben ’0’ und ’1’ auch Werte für ’X’ (unknown), ’Z’ (high-impedance) sowie verscheidene Treiberstärken). Dabei werden neben den Typen auch logische (and, or, not, xor…), arithmetische (+, −, ∗…) und Vergleichsoperatoren (=, / =, >, <…) auf diesen Typen definiert. Beispielsweise gibt es, für das am häufigsten genutzte Package STD LOGIC 1164, noch zusätzliche Erweiterungen die eine unsigned- oder signed-Zahlendarstellung (2-Komplement) annehmen und die Operatoren entsprechend definieren. Durch das Overloading können diese dann vom Benutzer wie gewohnt gehandhabt werden. Für Funktionen mit zwei Argumenten ist dabei die Benutzung in infix-Notation möglich.

In dem Beispiel wird eine Addition für einen 4-bit bit vector definiert.^{8}

\underline{Beispiel:} function "+" (A, B: bit vector (3 downto 0)) return bit vector is
variable SUM: bit vector (3 downto 0);
variable CARRY: bit;
begin
CARRY := '0';
for I in 0 to 3 loop
  SUM(I)  := A(I) xor B(I) xor CARRY;
  CARRY   := ((A(I) and B(I)) or (A(I) and CARRY) or (B(I) and CARRY));
end loop;
return SUM;
end;

8Standardmäßig ist die Addition auf bit vector nicht möglich!

6 Signale

Während die VHDL-Elemente aus Verhaltensbeschreibungen (Prozesse, Variablen und sequentielle Anweisungen) ihre direkte Entsprechung in Programiersprachen haben, haben Signale und parallele Blöcke Eigenschaften, die typisch sind für Strukturbeschreibungen und deren Simulation.

In VHDL stellen Signale die einzige Möglichkeit dar, quasi als Leitungen die Elemente struktureller Beschreibungen miteinander zu verbinden sowie die Kommunikation zwischen Prozessen zu ermöglichen. Bei der Simulation wird eine zeitliche Ordnung von Ereignissen — im Sinne von Ursache und Wirkung — über Signale geregelt.

6.1 Deklaration

Signale können an folgenden Stellen im VHDL-Code deklariert werden:

1. innerhalb eines package für globale Signale.
2. als port ... der entity Deklaration für entity-globale Signale.
3. innerhalb einer architecture als architecture-globale Signale.

\underline{Syntax:} in package oder architecture

signal signal name: type name [:= expression];

        als port einer entity
        ... signal name: in|out|inout|buffer type name;

Bei der Deklaration von Ein-/Ausgängen einer entity muß eine Signalrichtung spezifiziert werden:

in  Eingang, nur auf rechter Seite von Variablen-/Signalzuweisungen zulässig.
out  Ausgang, nur auf linker Seite von Signalzuweisungen zulässig.
inout bidirektionale Leitung, kann beliebig in Code benutzt werden.

buffer prinzipiell ein Ausgang (nur ein Treiber), kann intern aber auch auf rechter Seite von Zuweisungen benutzt werden.

\underline{Beispiel:} package SIGDECL is

           signal VCC: std logic := '1';  globale Signale

           signal GND: std logic := '0';
         end SIGDECL;

         entity MUXFF is                                     entity-globale Signale

           port (  DIN: in bit;
                   SEL: in bit;
                   CLK: in bit;

DOUT: buffer bit);  wird intern benutzt

           signal NOUT: bit;
         end MUXFF;
         ...

    architecture STRUCT of MUXFF is

      signal MOUT: bit;                           architecture-globale Signale

    begin
      ...

[figure: O; MUX; B; A; S; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; DFF; C; D; Q; O; I; NOT; DOUT; NOUT; MOUT; CLK; SEL; DIN]

6.2 Signalzuweisungen im Prozeß

Da Prozesse mit der Außenwelt (andere Prozesse, Entities…) nur über Signale verbunden werden können, werden Signalen (z.B. bei Ausgängen) Werte durch den Prozeß zugewiesen. Dabei sind allerdings einige Punkte zu beachten.

Verzögerungszeiten : Das Ziel der einer VHDL Beschreibung ist letztendlich die Simulation realer Schaltungen mit Verzögerungszeiten (Zeitkonstanten der elektrischen Netze). Zur Modellierung werden entsprechende Werte bei der Zuweisung an Signale angegeben. Für die Abarbeitung durch den Simulator heißt das, daß der neue Wert erst nach Ablauf der Verzögerungszeit auf dem Signal (für nachfolgende Eingänge) wirksam wird.

\underline{Syntax:} signal name <= expression [after time expr \{, expression after time expr\}];

Die Verzögerungszeit bei der Signalzuweisung (after...) ist relativ zu dem aktuellen Wert simulierter Zeit bei Erreichen der Zuweisung; auch eine Verzögerungszeit von 0 ist zulässig. In einer Signalzuweisung können gleich mehrere Werte, als zeitliche Abfolge, zugewiesen werden. Diese zeitliche Folge wird dabei vom Simulationsalgorithmus in die Liste zukünftiger Ereignisse aufgenommen (scheduling). ^{9}

\underline{Beispiel:} R   <= "1010";
         S   <= '1' after 4 ns, '0' after 7 ns;
         T   <= 1 after 1 ns, 3 after 2 ns, 6 after 8 ns;
         CLK <= not CLK after 50 ns;

9Der zeitliche Ablauf der Simulation ist in Abschnitt 1.4 genauer erläutert.

Aktivierung der Zuweisung : Obwohl Signalzuweisungen innerhalb eines Prozesses in einer Umgebung stehen, die in der Regel sequentiell abgearbeitet wird, werden solche Zuweisungen nicht in der Reihenfolge der sequentiellen Anweisungen wirksam. Signalzuweisungen werden erst bei Erreichen des nächsten wait in dem Prozeß oder, bei Verwendung einer sensitivity-list, am Ende des Prozesses wirksam. Daraus ergeben sich folgende Konsequenzen:

1. Signale können im Prozeß nicht wie Variable als Zwischenspeicher für Werte benutzt werden.

2. Es sollte in dem Prozeß nur eine einzige Zuweisung pro Signal vorkommen — nur ein Treiber.

Wegen der speziellen Eigenschaften der Signalzuweisung kommt es (gerade bei VHDL Anfängern) oft zu Fehlern, deshalb noch einige Beispiele:

\underline{Beispiel:} X <= Y;  beide Anweisungen werden bei dem wait gleichzeitig ausgeführt:
Y <= X;  ⇒ die Werte von X und Y werden vertauscht
wait ...  ⇒ die Reihenfolge der Zuweisungen ist irrelevant
V := 1;                                           V wird 1 — sofort
S <= V;                                 S wird V (also 1) — bei wait
A := S;                             A erhält alten Wert von S — sofort

              wait ...

X <= 1;  Achtung: wird durch zweite Zuweisung unwirksam!

              Y <= 3;                                        Y wird 3 — bei wait

X <= 2;  überschreibt obige Zuweisung: X wird 2 — bei wait

              wait ...

6.3 Implizite Typauflösungen und Bustreiber

Alle bisher beschriebenen Signalzuweisungen gingen von einem Treiber pro Signal aus. Um Hardwarestrukturen wie (bidirektionale) Busse, wired-or, wired-and u.s.w. beschreiben zu können, müssen besondere Mechanismen (resolution function) eingeführt werden.

Standardmäßig ist die Behandlung von Signalen mit mehreren Treibern in VHDL nicht vorgesehen; der Grund dafür ist, daß sich, abhängig von der verwendeten Schaltungstechnik, entweder wired-or, wired-and oder anderes (logisches) Verhalten ergibt. Dementsprechend ist es den Herstellern überlassen, in entsprechenden Packages, Typdeklarationen für mehrwertige Logik und solche Auflösungsfunktionen zu liefern.

Sollen mehrere Treiber auf ein Signal wirken, muß man folgendermaßen vorgehen — mehrere Treiber heißt, daß dem Signal in konkurrenten Anweisungen (parallel ablaufenden Prozessen, konkurrenten Signalzuweisungen, konkurrenten Prozeduraufrufen u.s.w.) Werte zugewiesen werden:

Typ und Untertyp : Zu einem entsprechenden Datentyp wird ein Untertyp (subtype) deklariert, der mit einer Auflösungsfunktion verbunden ist.

\underline{Syntax:} subtype subtype name is resolution func name type name;

Bei Signalzuweisungen auf ein Signal vom Typ subtype name wird implizit die mit dem Typ verbundene Funktion aufgerufen und berechnet den Wert des Signals.

Analog zu dem subtype kann auch ein aufzulösendes Signal deklariert werden als: signal name : resolution func name type name;

Auflösungsfunktion : Die resolution function wird wie eine normale Funktion deklariert und hat folgende Eigenschaften wie gewohnt gilt:

– Argumente haben den Modus input und werden als pass by value übergeben.
– Die Funktion liefert einen Wert zurück.

bei Auflösungsfunktionen gilt zusätzlich:

– Als Argument der Funktion wird ein Array variabler Länge mit Elementen type name übergeben.

– Der Funktionswert ist vom ursprünglichen Typ: type name.

– Die Funktion ist mit einem subtype verbunden. Bei jeder Signalzuweisung auf diesen Typ wird sie aufgerufen.

In dem Beispiel wird eine Auflösungsfunktion in Form eines wired-or auf einem 4-wertigen Datentyp beschrieben. Zwei Prozesse, die tristate-Treiber modellieren, benutzen ein gemeinsames Ausgangssignal.

\underline{Beispiel:} 4-wertiger Typ und entsprechender Array-Typ für Funktion

   type BIT4 is ('X', '0', '1', 'Z');
   type BIT4 VECTOR is array (integer range <>) of BIT4;

Auflösungsfunktion

   function WIRED OR (INP: BIT4 VECTOR) return BIT4 is

     variable RESULT: BIT4 := '0';  Ergebnis, Bus mit pull-down

   begin

     for I in INP'range loop  für alle Eingänge

       if INP(I) = '1' then
         RESULT := '1';

exit;  ’raus aus der Schleife

       elsif INP(I) = 'X' then
         RESULT := 'X';

       else null;                                   INP(I) = 'Z' oder = '0'

       end if;
     end loop;
     return RESULT;
   end WIRED OR;

Untertyp mit Auflösungsfunktion

subtype RESOLVED BIT4 is WIRED OR BIT4;
...
architecture BEHAVE of TRISTATE is

signal ASEL, BSEL: boolean;  Selektoren
signal SIGA, SIGB: BIT4;  Eingänge
signal SIGS: RESOLVED BIT4;  Ausgangssignal

begin

SOURCE1: process (ASEL, SIGA)  erste Quelle

begin
  SIGS <= 'Z';
  if (ASEL) then
    SIGS <= SIGA;
  end if;
end process;

SOURCE2: process (BSEL, SIGB)  zweite Quelle

begin
  SIGS <= 'Z';
  if (BSEL) then
    SIGS <= SIGB;
  end if;
end process;
end BEHAVE;

[figure: ASEL; BSEL; SIGS; SIGB; SIGA]

Für den Datentyp std_logic sind in dem Package STD_LOGIC_1164 Auflösungsfunktionen definiert: die Typen std_logic / std_logic_vector sind, mit einer Auflösungsfunktion versehene, Untertypen zu std_ulogic / std_ulogic_vector (unresolved).

Als Beispiel für den Umgang mit bidirektionalen Bussen, wird nachfolgend ein 4-bit Bustreiber/-empfänger modelliert.

\underline{Beispiel:} library IEEE;
 use IEEE.std logic 1164.all;
 entity BUSIO is
   port( OEN:    in std logic;
         IBUS:   in std logic vector (3 downto 0);
         OBUS:   out std logic vector (3 downto 0);
         IOBUS:  inout std logic vector (3 downto 0));
 end BUSIO;
 architecture BEHAV of BUSIO is
   begin
     P: process (OEN, IBUS, IOBUS)
     begin

       if (OEN = '1') then  Bus treiben

         IOBUS <= IBUS;

else  Bus nur lesen
IOBUS <= "ZZZZ";  explizite Zuweisung von 'Z'

       end if;
       OBUS <= IOBUS;
     end process;
   end BEHAV;

6.4 Attribute

Neben den typgebundenen Attributen gibt es in VHDL auch Attribute, die sich auf Signale beziehen. Mit Hilfe dieser Attribute können VHDL-Beschreibungen erstellt werden, die dynamisches Signalverhalten berücksichtigen. So können zur Laufzeit des Simulators über Attribute, Simulationsereignisse und Zeitpunkte ausgewertet werden.

\underline{Syntax:} aktueller Zeitpunkt signal'event true, wenn event (Signaländerung) signal'active true, wenn transaction (Signalzuweisung)

vorheriger Zeitpunkt signal'last event Zeitdifferenz zur letzten Signaländerung signal'last value Wert vor der letzten Signaländerung signal'last active Zeitdifferenz zur letzten Signalzuweisung

\underline{Beispiel:} entity DFLOP is  D-Type FF

port (  CLK, D: in std logic;
        Q: out std logic)
end DFLOP;
architecture BEHAV of DFLOP is
begin
process (CLK)
begin

if  (CLK = '1') and             CLK ist 1 und der Wert hat sich geändert
(CLK'event) and  (kann wegfallen da CLK in sensitivity-list)

      (CLK'last value = '0')  und der letzte Wert war 0 (wegen `X`...)

then  Q <= D;  ⇒ Vorderflanke

  end if;
end process;
end BEHAV;

7 Konkurrente Beschreibungen

Um die gleichzeitige Aktivität von Hardwarekomponenten auszudrücken, dienen konkurrente Beschreibungsformen.

Prozeß : Die wichtigste konkurrente Anweisung, der process, wurde schon als Umgebung sequentieller Anweisungen angesprochen,^{10} seine Merkmale sind:

– alle Prozesse sind parallel aktiv.

– ein Prozeß definiert einen Bereich in dem Anweisungen (programmiersprachenähnlich) sequentiell ausgeführt werden, um Verhalten zu beschreiben.

– ein Prozeß muß entweder eine sensitivity-list oder explizite wait-Anweisungen beinhalten.

– innerhalb des Prozesses können Signale aus entity und architecture gelesen und verändert werden.

Prozeßabarbeitung Da ein Prozeß in VHDL letztendlich das Verhalten eines Hardwareelementes modellieren soll, das ständig aktiv ist, hat ein Prozeß einige spezielle Eigenschaften:

Abarbeitung : Ein Prozeß kann als eine unbegrenzte Schleife verstanden werden. Bei Beginn der Simulation wird, quasi als Initialisierung, jeder Prozeß aktiviert und bis zu einem wait ausgeführt. Anschließend wird die Prozeßausführung entsprechend der Bedingung der wait-Anweisung unterbrochen. Wird der Prozeß später durch Erfüllung der wait-Bedingung wieder aktiviert, werden die Anweisungen von dort ausgehend sequentiell weiter ausgeführt bis ein nächstes wait erreicht wird. Ist der Prozeßcode zu Ende (end process;), so beginnt die Abarbeitung von vorn. Man kann sich dies vorstellen als:

\underline{Beispiel:} process ...
         begin

loop;  Start der Schleife

             ...

wait ...  mindestens ein wait, bzw. sensitivity-list

             ...

end loop;  Ende der Schleife

         end process;

Aktivierung : Wie oben schon erläutert, wird ein Prozeß durch den Simulator sequentiell abgearbeitet, dann an einer oder mehreren Stellen unterbrochen und bei Eintreten bestimmter Ereignisse event wieder aktiviert. Daraus ergibt sich, daß ein Prozeß mindestens eine wait-Anweisung oder eine sensitivity-list enthalten muß. Die sensitivity-list entspricht einem waiton... am Ende des Prozesses.

10in Abschnitt 5, Seite 24

\underline{Beispiel:} process (A, B)  sensitivity-list

             begin
               ...
             end process;

— ist äquivalent zu —

             process
             begin
               ...
               wait on A, B;
             end process;

Soll ein Datenfluß beschrieben werden, so entspräche jede Operation einem Prozeß der jeweils nur eine einzige Anweisung enthält. Als vereinfachte Form stehen dafür konkurrente Anweisungen zur Verfügung. Diese Anweisungen stehen innerhalb der architecture und entsprechen jede einem eigenen Prozeß. Ihre Reihenfolge im VHDL-Code ist irrelevant.

konkurrente Signalzuweisungen : sind zu einem Prozeß äquivalent, der nur aus einer Signalzuweisung mit entsprechender sensitivity-list besteht.

\underline{Syntax:} [label:] signal name <= expression [after time expr];

Die Anweisung wird aktiviert, wenn sich eines der Signale ändert, das auf der rechten Seite der Zuweisung steht.

\underline{Beispiel:} architecture VER1 of MUX is
         begin
           OUTPUT <= A (INDEX);
         end VER1;

— ist äquivalent zu —

         architecture VER1 of MUX is
         begin
           process (A, INDEX)
           begin
             OUTPUT <= A (INDEX);
           end process;
         end VER1;

geschützte Signalzuweisungen : sind eine besondere Form der konkurrenten Signalzuweisungen. Die Zuweisung wird nur dann durchgeführt, wenn ein Signal GUARD von Typ boolean den Wert true hat. Dieses Signal kann explizit vom Designer deklariert und benutzt worden sein, kommt aber üblicherweise als implizites Signal aus einem geschützten Block (siehe Seite 44).

\underline{Syntax:} [label:] signal name <= guarded expression [after time expr];

bedingte Signalzuweisungen : sind zu einem Prozeß äquivalent, der nur aus einer if-Anweisung und Signalzuweisungen nach der Verzweigung besteht. Auch geschachtelte

if...elsif... sind möglich.

\underline{Syntax:} [label:] signal name <= expression when condition else {expression when condition else} expression;

Die Anweisung wird aktiviert, wenn sich eines der Signale ändert, das auf der rechten Seite der Zuweisung steht (in Ausdruck oder Bedingung).

\underline{Beispiel:} Z <=  A when (X > 3) else
               B when (X < 3) else
               C;

selektive Signalzuweisungen : sind zu einem Prozeß äquivalent, der nur aus einer case-Anweisung und Signalzuweisungen nach der Verzweigung besteht.

\underline{Syntax:} [label:] with expression select

signal name <= expression when value{, expression when value};

Die Anweisung wird aktiviert, wenn sich eines der Signale der Auswahlbedingung oder der Ausdrücke auf der rechten Seite der Zuweisung ändert.

\underline{Beispiel:} with MYSEL select
           Z <=  A when 15,
                 B when 22,
                 C when 28;

konkurrente Prozeduraufrufe : entsprechen einem Prozeß der nur einen Prozeduraufruf beinhaltet. Die Prozedur hat Signale als in, out und inout Parameter. Der Aufruf wird aktiviert, wenn sich eines der Parametersignale ändert.

\underline{Beispiel:} architecture ...
           procedure VEC2INT
             ( signal S: in bit vector;
               signal ZFLAG: out boolean;
               signal Q: inout integer;) is
           ...
         begin
           VEC2INT (BITVEC, FLAG, NUMBER);
           ...

— ist äquivalent zu —

         architecture ...

           procedure VEC2INT ...  Deklaration wie oben

           ...
         begin
           process (BITVEC, NUMBER)
           begin
             VEC2INT (BITVEC, FLAG, NUMBER);
           end process;
           ...

Block : Um konkurrente Anweisungen (hierarchisch) zu gruppieren, kann der block-Befehl benutzt werden. Ein Block enthält Deklarationen von Datentypen, Signalen u.s.w. die nur lokal benötigt werden; der eigentliche Anweisungsteil besteht aus konkurrenten Anweisungen wie oben beschrieben. Geschützte Blöcke beinhalten zusätzlich einen boole’schen Ausdruck guard expression der ein implizit vorhandenes Signal GUARD (Typ boolean) treibt. Dieses Signal kann innerhalb des Blocks für die Kontrolle von Anweisungen genutzt werden — wegen des direkten Bezugs auf GUARD sind dies meist geschützte Signalzuweisungen.

\underline{Syntax:} label: block [(guard expression)] [use clause] [subprogram decl subprogram body] [type decl] [subtype decl] [constant decl] [signal decl] [component decl]

        begin

[concurrent statements]

        end block [label];

8 Strukturbeschreibungen

Bei dem strukturellen Beschreibungsstil in VHDL werden die Komponenten einer Architektur und deren Verbindungen untereinander beschrieben. Dazu werden Komponenten deklariert und dann Instanzen dieser Komponenten erzeugt, wobei die verbindenden Signale auf die Anschlüsse abgebildet werden. Die Instanziierung einer Komponente wird vom Simulator wie eine konkurrente Anweisung behandelt.

\underline{Syntax:} component declaration

component component name

[generic ( generic list: type name [:= expression] {;

generic list: type name [:= expression]} );]

          [port ( signal list: in|out|inout|buffer type name {;

signal list: in|out|inout|buffer type name} );]

        end component;

component instantiation

component label: component name port map (signal mapping);

Die Abbildung der Signale an den Anschlüssen kann bei der Instanziierung entweder über die Position oder über den Namen erfolgen, bei der Angabe des Namens gilt wie üblich: declaration name => signal name.

Wird an einen der Ports kein Signal angeschlossen (z.B. bei nicht benutzten Ausgängen), so kann der reservierte Bezeichner open benutzt werden. Anstelle der Signalnamen ist auch ein Funktionsaufruf möglich, dadurch können Typkonvertierungen direkt bei der Instanziierung von Komponenten vorgenommen werden.

\underline{Beispiel:} entity RSFF is
         port (  SET, RESET: in bit;
                 Q, QBAR: inout bit);
         end RSFF;
         architecture NETLIST of RSFF is
           component NAND2
             port (A, B: in bit; C: out bit);
           end component;
         begin
           U1: NAND2 port map (SET, QBAR, Q);
           U2: NAND2 port map (Q, RESET, QBAR);
         end NETLIST;

— bei Instanziierung mit Signalabbildung über Namen: —

           U1: NAND2 port map (A => SET, C => Q, B => QBAR);

[figure: A; B; C; A; B; C; RESET; SET; Q; QBAR; U1; U2]

8.1 Erzeugung von Instanzen

Oft werden bei Hardwareaufbauten array-artige Anordnungen von Komponenten benötigt (z.B. entsprechend der Bitbreite, Größe des Speichers…). Um solche Anordnungen zu beschreiben, kann in VHDL die generate-Anweisung benutzt werden. Sie erlaubt:

1. die Wiederholung von Strukturen entsprechend einer for...loop Schleife.
2. die Auswahl bestimmter Instanziierungen durch if...then Bedingungen.

\underline{Syntax:} generate label: for variable in range generate

concurrent statement  i.A. Instanziierung

end generate [generate label];

generate label: if (condition) generate

concurrent statement end generate [generate label];

[figure: .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; DFF; C; D; Q; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; DFF; C; D; Q; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; DFF; C; D; Q; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; .; DFF; C; D; Q; CLK; Z(1); SIN; Z(2); Z(3); SOUT]

\underline{Beispiel:} entity SHIFT is
port (  SIN, CLK: in bit;
        SOUT: out bit);
end SHIFT;

gleichartiger Aufbau des Schieberegisters

architecture NETLIST1 of SHIFT is
  component DFF
    port (D, CLK: in bit; Q: out bit);
  end component;
  signal Z: bit vector (0 to 4);

         begin
           Z(0) <= SIN;
           GF: for I in 0 to 3 generate
             UI: DFF port map (Z(I), CLK, Z(I+1));
           end generate;
           SOUT <= Z(4);
         end NETLIST1;

Ausnahmebehandlung von Ein- und Ausgang des Schieberegisters

         architecture NETLIST2 of SHIFT is
           component DFF
             port (D, CLK: in bit; Q: out bit);
           end component;
           signal Z: bit vector (1 to 3);
         begin
           GF: for I in 0 to 3 generate
             GI1: if (I = 0) generate
               U0: DFF port map (SIN, CLK, Z(I+1));
             end generate;
             GI2: if ((I > 0) and (I < 3)) generate
               UI: DFF port map (Z(I), CLK, Z(I+1));
             end generate;
             GI3: if (I = 3) generate
               U3: DFF port map (Z(I), CLK, SOUT);
             end generate;
           end generate;
         end NETLIST2;

8.2 Benutzung von Packages

Bei den obigen Beispielen wurde die Deklaration der Komponenten immer innerhalb der architecture gemacht. Bei sich dauernd wiederholenden Komponenten, zum Beispiel aus der Zellbibliothek eines Herstellers, kann man sich durch die Benutzung von Packages (die meist schon von den Herstellern mitgeliefert werden) diese Arbeit sparen.

Dazu wird mit Hilfe einer use-Anweisung das entsprechende Package für die Benutzung verfügbar gemacht. Das package selber enthält nur die Komponentendeklaration, die Entity-Deklaration und die zugehörige(n) Architektur(en) können sich in einer anderen Design-Unit befinden.

\underline{Beispiel:} architecture S of COMPARE is
component XR2
  port (X, Y: in bit; Z: out bit);
end component;
component INV
  port (X: in bit; Z: out bit);
end component;
signal I: bit;
begin
U0: XR2 port map (A, B, I);
U1: INV port map (I, C);
end S;

— ist äquivalent zu —

package XYZ GATES                  package mit Deklaration der Komponenten

component XR2
  port (X, Y: in bit; Z: out bit);
end component;
component INV
  port (X: in bit; Z: out bit);
end component;
end XYZ GATES;

use WORK.XYZ GATES.ALL;  Benutzung des package XYZ GATES

architecture T of COMPARE is
signal I: bit;
begin
U0: XR2 port map (A, B, I);
U1: INV port map (I, C);
end T;

8.3 Konfigurationen

Dadurch, daß zu einem entity verschiedene Realisierungen als architecture möglich sind, werden die folgenden Eigenschaften von VHDL erst ermöglicht:

– Schrittweise top-down Verfeinerung (von black-box Verhalten zu Struktur)
– Untersuchung von Alternativen
– Unterstützung von Versionen

Durch Konfigurationen werden den Komponenten in strukturellen Beschreibungen konkrete Architekturen zugeordnet. Diese Konfigurationen können an zwei Stellen vorgenommen werden:

1. innerhalb der architecture : in Form einer Konfigurationsanweisung.

\underline{Syntax:} for label: entity name use entity [lib name.]entity name(architecture name);

Wurde keine explizite Konfiguration vorgenommen, so wird die jeweils (zeitlich) zuletzt analysierte architecture benutzt, die null Konfiguration.

\underline{Beispiel:} entity XR2 is  Deklaration des entity

           port (X, Y: in bit; Z: out bit);
         end XR2;

         architecture SLOW of XR2 is  erste architecture

         begin
           Z <= X xor Y after 1.0 ns;
         end SLOW;

         architecture FAST of XR2 is  alternative architecture

         begin
           Z <= X xor Y after 0.5 ns;
         end FAST;

Benutzung von XR2 in COMPARE

         architecture U of COMPARE is

           for U0: XR2 use entity WORK.XR2(FAST);  Konfiguration für XR2

           signal I: bit;
         begin

           U0: XR2 port map (A, B, I);  explizite Konfiguration

U1: INV port map (I, C);  implizite Konfiguration

         end U;

2. außerhalb der architecture : können mit Hilfe der configuration-Anweisung Architekturen ausgewählt werden. Dabei ist eine Konfiguration eine seperate Design-Einheit, die analysiert und simuliert werden kann. Mit Konfigurationen lassen sich folgende Zuordnungen treffen:

Architecture — Entity Wenn für ein entity mehrere Architekturen definiert sind, kann ausgewählt werden, welche architecture in der Simulation der Schaltung benutzt wird.

\underline{Syntax:} configuration configuration name of entity name is for architecture name

               end for;

end configuration name;

In dem Beispiel werden für das xor-Gatter zwei Konfigurationen erstellt, die dann als ONE und TWO, beispielsweise zur Simulation des XOR, benutzt werden können.

\underline{Beispiel:} configuration ONE of XR2 is                 ONE wählt FAST aus

for FAST
end for;
end ONE;

configuration TWO of XR2 is                 TWO wählt SLOW aus

for SLOW
end for;
end TWO;

Architecture — Component In diesem Fall wird die Auswahl der Architekturen bei hierarchischen Beschreibungen festgelegt. Ist eine Schaltung strukturell (⇒ Hierarchie) beschrieben und sind für die instanziierten Komponenten mehrere Architekturen vorhanden, so kann bei der configuration festgelegt werden, welche der möglichen Architekturen für eine Instanz benutzt wird.

\underline{Syntax:} configuration configuration name of entity name is

for architecture name

for label|others|all: comp entity name use entity [lib name.]comp entity name(comp architecture name); | configuration [lib name.]configuration name;

end for;
...
end for;
...

end configuration name;

In dem Beispiel sei MCOMP eine Schaltung die mehrere Instanzen von XR2 und INV enthält.

\underline{Beispiel:} configuration TRY1 of MCOMP is
for STRUCT
for U0: XR2 use entity WORK.XR2(FAST);
end for;

— oder —

for U0: XR2 use configuration WORK.ONE;
end for;
for others: XR2 use configuration WORK.TWO;
end for;
for all: INV use configuration WORK.INV(FAST);
end for;
end for;
end TRY1;

\underline{Achtung:}

Bei den meisten VHDL-Simulatoren ist die Simulation eines Entity, das Komponenten instanziiert, nur über eine Konfiguration möglich. Diese ist auch dann notwendig, wenn für die Komponenten des (hierarchischen) Entwurfs nur eine Architektur vorhanden ist. Üblicherweise ist dies bei Testumgebungen, die den eigentlichen Entwurf referenzieren, der Fall. Hier genügt dann die default Konfiguration.

\underline{Syntax:} configuration configuration name of entity name is for architecture name

                    end for;

end configuration name;

Konfigurationen erlauben weiterhin eine neu-Abbildung der Anschlüsse der Komponenten-Deklaration (component...) zu denen des zugrundeliegenden Entwurfs (entity...). Üblicherweise verwendet man zwar für die Deklaration der Komponenten die entsprechenden Zeile (port...) des entity, aber in einigen Fällen sind solche Umordnungen notwendig.

• Beispielsweise kann mit generischen Zellbibliotheken gearbeitet werden, die dann durch Konfigurationen auf Zielbibliotheken verschiedener Hersteller abgebildet werden.

• Außerdem können Elemente des Entwurfs, durch Spezialisierung anderer, ähnlicher Teile ersetzt werden. In dem Beispiel werden alle Inverter durch entsprechend beschaltete Nand-Gatter ersetzt.

     \underline{Beispiel:} configuration NANDY of COMPARE is
                for S
                  for all: INV use entity WORK.NAND2(BEHAVE)
                    port map (A => A, B => Vcc, Z => Z);
                  end for;
                end for;
              end NANDY;

8.4 Parametrisierung durch generische Werte

Während VHDL-Entwürfe über Signale an den Ein- und Ausgängen im Sinne einer Struktur in der Umgebung eingebunden werden, kann deren Verhalten über generische Werte (quasi als Variablen) verändert werden.

Dieser Mechanismus wird beispielsweise dazu benutzt, Verzögerungszeiten von Elementen außerhalb des entity zu definieren. So kann ein Hersteller bei Änderung der Bibliotheken (z.B. Umstellung von 1.0 μ- auf 0.7 μ-Prozeß) seine Verhaltensmodelle beibehalten und nur die Schaltzeiten der einzelnen Elemente werden neu übergeben.

Generische Werte werden bei der Deklaration des entity vor den Ein-/Ausgängen (port) angegeben und können in der entsprechenden architecture wie Konstanten benutzt werden.^{11} Die Übergabe, bzw. die Festlegung konkreter Werte kann an folgenden Stellen stattfingen:

1. default-Wert bei der entity-Deklaration

2. default-Wert bei der component-Deklaration in der architecture oder in einem

    package

3. aktueller Wert bei der Instanziierung in der architecture
4. aktueller Wert bei einer Konfiguration der architecture

Die Abbildung generischer Werte erfolgt jeweils über den Namen, als: declaration name => actual value.

\underline{Syntax:} Deklaration in entity und component

generic ( generic name : type name [:= default value]{; generic name : type name [:= default value]} );

Instanziierung

component label: component name

          generic map (value mapping)

port map (signal mapping);

Gerade bei Zellbibliotheken sind die generischen Werte, zusammen mit der Deklaration der Komponenten, in seperaten packages festgelegt. Weiterhin ist es möglich, generische Werte in Konfigurationen zu spezifizieren. So können verschiedene Konfigurationen benutzt werden, um unterschiedliche Geschwindigkeitsklassen (min-, typ-, max-delay) auszuwählen.

\underline{Beispiel:} entity XR2 is

generic (M: time := 1.0 ns);  Verzögerungszeit als generischer Wert

           port (X, Y: in bit; Z: out bit);  Vorbesetzung mit Default

         end XR2;
         ...
         architecture GENERAL of XR2 is
         begin

Z <= X xor Y after m;  Benutzung wie Konstante

         end GENERAL;

11In den Beispielen werden generische Werte nur in strukturellen Beschreibungen, zur Angabe der Verzögerungszeit, eingesetzt. Sie können aber genauso auch in Verhaltensmodellen (process) wie ein konstanter Wert verwendet werden.

generischer Wert bei Instanziierung

architecture S of COMPARE is
signal I: bit;
component XR2
  generic (M: time);
  port (X, Y: in bit; Z: out bit);
end component;
...
begin
U0: XR2 generic map (M => 1.5 ns)
        port map (A, B, I);
...
end S;

generischer Wert bei component-Deklaration

architecture S of COMPARE is
signal I: bit;
component XR2
  generic (M: time := 1.5 ns);
  port (X, Y: in bit; Z: out bit);
end component;
...
begin
U0: XR2 port map (A, B, I);
...
end S;

generischer Wert bei component-Deklaration in extra package

package XYZ COMPONENTS is
component XR2
  generic (M: time := 1.5 ns);
  port (X, Y: in bit; Z: out bit);
end component;
...
end XYZ COMPONENTS;

generischer Wert in der configuration

configuration LATE of COMPARE is
for S
  for U0: XR2 use entity WORK.XR2(GENERAL)
    generic map (M => 1.5 ns);
  end for;
end for;
end LATE;

9 Libraries und Packages

Ein package ist eine eigene VHDL-Einheit, kann also compiliert werden und dient dazu, oft benutzte Deklarationen und Unterprogramme zu sammeln. Dies sind beispielsweise Deklarationen für: Typen, Untertypen Konstante Komponenten Unterprogramme (Prozeduren und Funktionen) …

Packages können (müssen aber nicht unbedingt) weiter in header und body unterteilt werden. Der header enthält dabei die nach außen sichtbaren Teile, während Implementationen in dem body stehen; beide Teile können in getrennten Dateien enthalten sein — die Idee ist auch hier wieder, daß bei Änderungen nur möglichst kleine Teile des VHDL-Codes ausgetauscht und neu analysiert werden müssen: hier der Package-body. Diese Unterteilung ist in folgenden zwei Fällen sinnvoll, bei Unterprogrammen sogar notwendig:

1. zurückgestellte (deferred) Konstante: Die Deklaration der Konstanten befindet sich im header, während die Festlegung eines Wertes im body stattfindet.

2. Unterprogramme — Funktionen und Prozeduren: Im Package-header ist nur die Deklaration des Unterprogramms, der Programmrumpf befindet sich im body.

\underline{Syntax:} package package name is [type decl] [subtype decl] [constant decl] [deferred constant decl] [subprogram decl] [subprogram header decl] [component decl] end [package name];

        package body package name is

[deferred constant value] [subprogram body] end [package name];

Um auf die Deklarationen aus Packages zuzugreifen, werden diese mit der use Anweisung in anderen Entwürfen benutzbar gemacht. Befinden sich diese Packages nicht in der Bibliothek WORK (Voreinstellung), so muß außerdem die Bibliothek mit der library Anweisung bekanntgegeben werden.

\underline{Syntax:} [library library name list;]  Voreinstellung für die Bibliothek ist WORK

use [library name.]package name.item name; | [library name.]package name.all;

Nach obigen Deklarationen kann auf Elemente aus Bibliotheken und Packages direkt über deren Name item name zugegriffen werden. Als zweite, allgemeine Möglichkeit kann auch der komplette Name angegeben werden: [library name.]package name.item name.

\underline{Beispiel:} Benutzung einer Konstantendeklaration

package MY DEFS is
  constant UNIT DELAY: time := 1 ns;
end MY DEFS;
entity COMPARE is
  port (  A, B:in bit;
          C: out bit);
end COMPARE;
...

library DEMO LIB;  wenn nicht WORK

use DEMO LIB.MY DEFS.all;
...
architecture DFLOW of COMPARE is
begin
  C <= not (A xor B) after UNIT DELAY;
end DFLOW;

… als deferred constant

package MY DEFS is

  UNIT DELAY: time;  nur Deklaration

end MY DEFS;
package body MY DEFS is

  constant UNIT DELAY: time := 1 ns;  Festlegung des Wertes

end MY DEFS;

Unterprogramm

package TEMPCONV is

  function C2F (C: real) return real;  nur Deklaration

  function F2C (F: real) return real;
end TEMPCONV;
package body TEMPCONV is

  function C2F (C: real) return real is  Funktionsrumpf

  begin
    return (C * 9.0 / 5.0) + 32.0;
  end C2F;
  function F2C (F: real) return real is
  ...
end TEMPCONV;

Zusätzliche Libraries und Packages werden im VHDL-Entwurf aus folgenden Gründen benutzt:

Zusammenfassung eigener Deklarationen : wie schon in den Beispielen gezeigt, können Deklarationen, die in mehreren (Sub-) Designs benötigt werden, in Form von Packages gesammelt werden — nur für einen Entwerfer bei Benutzung der Default-Library: WORK oder sogar für eine Arbeitsgruppe, Abteilung o.ä. bei zusätzlichen Bibliotheken.

Erweiterungen von VHDL : die Hersteller von VHDL-Werkzeugen bieten über eigene Bibliotheken und in ihnen enthaltene Packages Ergänzungen zu dem ”Standard-VHDL“ an. Dies sind meist zusätzliche Datentypen und Funktionen für: mehrwertige Logik (std_logic_1164) und Operationen darauf. mathematische Funktionen (Wurzel, Exponential-, trigonometrische- …). Hilfsroutinen (Zufallszahlengeneratoren, Queue-Modellierung…). Konvertierungsfunktionen zwischen den einzelnen Datentypen.

Benutzung von Zellbibliotheken : die ASIC-Hersteller stellen ihre Zellbibliotheken für die Simulation von Strukturbeschreibungen, bzw. deren Synthese, in Form von VHDL-Libraries zur Verfügung.

Die Abbildung von Bibliotheken, wie sie in VHDL benutzt werden, auf das Dateisystem eines Rechners geschieht außerhalb der Sprache VHDL (meist in Konfigurationsdateien).

10 VHDL und Synthese

VHDL als Hardwarebeschreibungssprache deckt mit seinen Ausdrucksmöglichkeiten alle im (digital) IC-Entwurf verwendeten Abstraktionsebenen ab. So kann das Verhalten kompletter Systeme mit abstrakten Datentypen modelliert (und simuliert) werden, während andererseits Netzlistenbeschreibungen mit Datentypen '0' und '1' einen Aufbau aus Logikgattern nachbilden. Damit ist VHDL der ideale Ausgangspunkt für Synthesewerkzeuge, da Ein- und Ausgabe der Programme in VHDL erfolgen kann, wobei abhängig von deren Möglichkeiten eine mehr oder minder abstrakte VHDL-Beschreibung verarbeitet wird.

Synthese bezeichnet hier die Transformation von Verhaltensbeschreibungen in Strukturbeschreibungen aus Elementen niedrigerer Abstraktionsebenen — im Idealfall aus Elementen einer Zellbibliothek eines Herstellers. Da sich mit zunehmender Abstraktion mehr Freiheitsgrade in Bezug auf Entwurfsentscheidungen ergeben, wird der Suchraum für mögliche Lösungen immer größer. Aber selbst auf der Logikebene hat man schon den tradeoff zwischen Platz und Geschwindigkeit: kleine Lösungen mit wenig Elementen, die aber durch Mehrfachbenutzung der Gatter viele Stufen umfassen ⇔ schnelle Schaltnetze mit wenigen Stufen (im Idealfall: zweistufig), die aber sehr groß sind.

In kommerziellen Werkzeugen wird heutzutage die Logiksynthese (Schaltnetze), die Synthese von Datenpfaden (Register, Funktionseinheit, Register, …) und die Synthese endlicher Automaten (synchrone Schaltwerke) relativ problemlos beherrscht. Bei funktionalen Beschreibungen höherer Ebenen zeigen Werkzeuge, die überwiegend aus dem universitären Bereich kommen, eine (notwendige) Spezialisierung — bezüglich der Zielarchitekturen, wie auch der Einsatzbereiche bzw. Aufgabenstellung ⇒ Einschränkung des Suchraums.

Wie schon angedeutet wurde, ist nicht jede VHDL-Beschreibung sinnvoller und/oder möglicher Ausgangspunkt für Synthesetools. Man spricht deshalb auch oft von synthesisready code. Das heißt:

1. Die Eingabe muß sich auf einem Level befinden, daß sie von den CAD-Werkzeugen verarbeitet werden kann — zur Zeit sind dies Beschreibungen, die im Bereich der Register-Transfer Ebene anzusiedeln sind. Gegebenenfalls müssen, im Sinne eines Top-Down Entwurfs, erste Verfeinerungen schon ”von Hand“ gemacht worden sein.

2. Die Eingabe muß gut synthetisierbar sein. Hinter dieser Aussage verbirgt sich die ganze Kunst beim Umgang mit Synthesewerkzeugen. Wie in Programmiersprachen lassen sich auch in VHDL Verhaltensweisen auf viele verschiedene Arten ausdrücken, wobei abhängig vom Werkzeug einige besonders gut für die Synthese geeignet sind, während andere als ”nicht synthethisierbar“ eingestuft werden oder nur zu ineffizienten Hardwarelösungen führen.

Neben der Art der Sprachbeschreibung wirken sich vor allem noch zwei weitere Einflüsse auf das Syntheseergebnis aus. Dies ist zum einen die Zielbibliothek – welche Elemente stellt ein Hersteller zur Verfügung –, zum anderen die Art und Weise, wie der Benutzer den Syntheseprozeß gesteuert hat. So bieten die meisten Systeme vielfältige Möglichkeiten um Randbedingungen einzustellen, wie:

– Schranken für die Fläche (area)
– Schranken für Signallaufzeiten (delay, transition time, arrival time)
– Zeitabhängigkeiten zwischen Signalen (clock to data)
– Belastung vorangeschalteter Stufen (load)
– Treiberleistung (fanout)

Durch die Angabe solcher Randbedingungen wird einerseits der Suchraum des Synthesesystems eingeschränkt, zum anderen können Anforderungen der späteren Schaltungsumgebung berücksichtigt werden ⇒ schneller, gezieltere Ergebnisse.

Da der ”synthetisierbare“ Sprachumfang von VHDL von dem verwendeten Werkzeug abhängt, folgen jetzt nur einige allgemeine Anmerkungen zu Strategien bei der Synthese und zu der Umsetzung von Sprachkonstrukten.

Verzögerungszeiten : sind bei Signalzuweisungen, in Bezug auf die Synthese, unsinnig, da sich die absoluten Zeitangaben nicht in Hardware realisieren lassen.

     \underline{Beispiel:} C <= A xor B after 5 ns;

Datentypen : werden bei der Synthese folgendermaßen verarbeitet:

Bit, Bit vector  : werden direkt umgesetzt
Std logic, … vector : werden direkt umgesetzt
Aufzählungstypen : werden automatisch durchnumeriert

Integer : werden umgesetzt (meist in 2-Komplement Zahlen). Durch Bereichseinschränkungen wird die Wortbreite festgelegt. Beispielsweise impliziert die Angabe range0to15 eine 4-bit unsigned Darstellung.

Real  : abhängig vom Synthesesystem

Prozesse und konkurrente Signalzuweisungen : Die meisten Werkzeuge erzeugen bei der Synthese für jeden Prozeß und jede Signalzuweisung entweder ein eigenes Schaltnetz oder ein eigenes Schaltwerk. Die Unterscheidung ist abhängig von bestimmten Beschreibungsformen, die eine zeitliche Abhängigkeit implizieren.

Schaltnetze : werden unter folgenden Bedingungen erzeugt:

Prozeß  : beschreibt nur Ausdrücke

: Variablen werden bei jeder Prozeßaktivierung initialisiert und dienen nicht als Zwischenspeicher

: es kommt nur ein wait, bzw. eine sensitivity-list vor

Signalzuweisung : das Ziel der Zuweisung kommt nicht auf der rechten Seite von

Ausdrücken vor

Als Operatoren können alle logischen und arithmetischen Operationen ausgeführt werden. Bei den Anweisungen erzeugen if und case typischerweise Multiplexerstrukturen, Schleifen führen zu Wiederholungen von Gattern — sofern sie nicht zeitliches Verhalten im Sinne von Schaltwerken ausdrücken.

Schaltwerke : werden unter folgenden Bedingungen erzeugt:

Prozeß  : beschreibt ein zeitliches Verhalten
: Signalzuweisungen sind von Bedingungen abhängig
: Variablen beinhalten Werte vorheriger Prozeßaktivierungen

: es werden typische, ereignisbezogene Signalabfragen durch-

                      geführt, wie if(CLK`event)and(CLK='1')

: es kommen mehrere wait Anweisungen vor

Signalzuweisung : das Ziel der Zuweisung steht auch auf der rechten Seite in einem

Ausdruck

Um die zeitliche Zwischenspeicherung zu realisieren, werden bei der Synthese Flipflops, bzw. Register generiert. Die Operatoren und Anweisungen werden als Schaltnetze (s.o.) an den Ein- und Ausgängen der Zeitglieder realisiert.

endliche Automaten

Eine besonders häufig verwendete Form von Schaltwerken sind endliche Automaten (Finite State Machine), die dazu benutzt werden, als Kontrolleinheit andere Werke zu steuern.

Sie werden in VHDL typischerweise dadurch beschrieben, daß eine Variable (oder ein Signal mit Zwischenspeicherung) existiert, die den aktuellen Zustand speichert. In dem Prozeß wird mit Hilfe einer einzigen großen case Anweisung, abhängig vom aktuellen Zustand verzweigt; dabei werden dann innerhalb dieser Verzweigung aus der Eingabe ein Nachfolgezustand und die Ausgabewerte berechnet.

10.1 Synopsys

Da die Art der Beschreibung stark von den eingesetzten Werkzeugen abhängt – wie schon oben angedeutet: durch unterschiedliche Synthesestrategien werden unterschiedliche Formulierungen bevorzugt –, können Beispiele nur exemplarisch zu bestimmten Syntheseprogrammen und deren Versionen angegeben werden. Dieser Abschnitt bezieht sich auf die Synthese mit dem Synopsys Design Compiler, V 3.1a.

Art der VHDL-Beschreibung Hinsichtlich der Abstraktion ist eine Synthese der Eingabe bis in der Bereich der Register-Transfer Ebene, teilweise sogar bis hin zur Hauptblockebene, möglich. Beispielsweise kann eine Strukturbeschreibung aus Elementen der RT-Ebene problemlos synthetisiert werden, wobei die einzelnen Komponenten durch Verhaltensbeschreibungen spezifiziert sind.

Bei der Wahl zwischen Verhaltens- oder Strukturbeschreibungen (einer niedrigeren Abstraktionsebene) gilt folgende Grundregel: Strukturen, die sich ein Entwerfer während des Designprozesses vorstellt, sollten auch als solche in die VHDL-Beschreibung eingebracht werden. Andernfalls ist es vergleichsweise schwierig eine komplexe Verhaltensbeschreibung so zu ändern, daß bestimmte ”Zielarchitekturen“ durch die Synthese erzeugt werden.

10.1.1 Behandlung von Beschreibungsformen in der Synthese

Für die Beschreibungen in einer architecture gelten folgende Grundregeln:

Instanziierungen bilden die logische Grundlage von (vorgegebenen) Hierarchien, sie werden direkt in die synthetisierte Struktur übernommen. generate-Anweisungen werden entsprechend wie einfache Instanziierungen von Komponenten direkt in Hardwarestrukturen umgesetzt.

\underline{Beispiel:} einfache Instanziierungen: Z = \overline{\overline{A ∧ B} ∧ \overline{C ∧ D}}

component ND2  Komponentendeklaration

           port (A, B: in bit; C: out bit);
         end component;
         ...
         signal TMP1, TMP2: bit;
         ...
         begin

           U1: ND2 port map(A, B, TMP1);  Instanziierungen

           U2: ND2 port map(C, D, TMP2);
           U3: ND2 port map(TMP1, TMP2, Z);
         end ARCHI1;

Instanziierungen mit generate: 8-bit Register

         component FF1  1-bit FF

           port (D, CLK: in bit; Q: out bit);
         end component;
         ...
         signal CLK:   bit;
         signal D, Q:  bit vector(0 to 7);
         ...
         begin

           GEN: for I in D'range generate  8-fache Instanziierung

             U: FF1 port map (D(I), CLK, Q(I));
           end generate GEN;
         end ARCHI2;

Werden Entities in der Hierarchie mehrfach instanziiert, so sind bei deren Behandlung durch den Syntheseprozeß drei Strategien möglich:

Generalisierung : das instanziierte Entity wird einmal synthetisiert, anschließend verweist jede Instanziierung auf dieses Element (Design Attribute: Don't

    Touch).

Individualisierung : entsprechend der Anzahl der Instanziierungen werden unterscheidbare Entities erzeugt, die dann individuell synthetisiert werden (Uniquify

    Hierarchy).

Der Vorteil dieser Methode ist, daß unterschiedliche Umgebungen (des Entities) berücksichtigt werden können und deshalb der Syntheseprozeß für einzelne Instanzen auch unterschiedlich optimierte Ergebnisse liefert. Solche Unterschiede können hervorgerufen werden durch: Ausgangslasten (⇒ andere Dimensionierung von Treibern und Logik), Belegung von Eingängen mit konstanten Werten (⇒ Logikminimierung) usw.

Auflösen der Hierarchie : führt prinzipiell zu vergleichbaren Ergebnissen wie die Individualisierung, ist aber wegen des Verlusts der Übersichtlichkeit nicht zu

empfehlen (ungroup -all -flatten).

Direkte Signalzuweisungen auf der Architekturebene (konkurrente, selektive und bedingte Signalzuweisungen) werden in entsprechende Schaltnetze umgesetzt.

\underline{Beispiel:} konkurrente Signalzuweisung (mit Operation)

    signal A, B, Z: bit;
    ...
    begin
      Z <= A and B;

bedingte Signalzuweisung

    signal A, B, C, Z: bit;
    ...
    begin
      Z <=  A when ASSIGN A = '1' else
            B when ASSIGN B = '1' else
            C;

selektive Signalzuweisung (Multiplexer)

    signal A, B, C, D, Z: bit;
    signal CONTROL: bit vector(1 down to 0);
    ...
    begin
      with CONTROL select
        Z <=  A when "00"
              B when "01"
              C when "10"
              D when "11"

Konkurrente Prozeduraufrufe entsprechen in ihrer Wirkung Prozessen in VHDL (mit entsprechender sensitivity list) und werden bei der Synthese wie diese behandelt.

Prozesse können, abhängig von der Verwendung der enthaltenen Signalzuweisungen, sowohl Schaltnetze als auch Schaltwerke beschreiben. In dem jetzt folgenden Abschnitt wird auf die Synthese von Prozessen noch genauer eingegangen.

10.1.2 VHDL-Prozesse

Das entscheidende Kriterium, wie der VHDL-Code in Prozessen synthethisiert wird, bzw. ob überhaupt eine Synthese möglich ist, ist die Art der Zuweisungen an Variablen des Prozesses oder an die Signale, die den Prozeß mit seiner Umgebung in der architecture verbinden. Dabei wird unterschieden, ob bei der Abarbeitung eines Prozesses Zuweisungen immer oder nur bedingungsabhängig wirksam werden. Im letzteren Fall werden speichernde Elemente (Register) erzeugt — inferred devices.

1. Schaltnetze ⇔ keine impliziten Register

Signale : Für ein Signal wird nur sequentielle Logik synthetisiert, wenn dem Signal bei jeder Prozeßaktivierung Werte zugewiesen werden. Dementsprechend müssen folgende Bedingungen gelten: entweder ist die Signalzuweisung nicht bedingungsabhängig oder bei Verzweigungen im Programmlauf des Prozesses (if und case) findet in allen Fällen eine Zuweisung statt. Außerdem darf eine if-Anweisung keine Bedingung enthalten, die eine Taktflanke impliziert.

\underline{Beispiel:} if-Anweisung

              signal A, B, C, P1, P2, Z: bit;
              ...
              P1: process
              begin
                if (P1 = '1') then
                  Z <= A;
                elsif (P2 = '0') then
                  Z <= B;
                else
                  Z <= C;
                end if;
                ...

case-Anweisung

              signal INVAL is integer range 0 to 15;
              signal Z1, Z2, Z3, Z4: bit;
              ...
              P2: process
              begin
                Z1 <= '0';    Z2 <= '0';
                Z3 <= '0';    Z4 <= '0';
                case INVAL is

                  when 0 =>           Z1 <= '1';  0
                  when 1 | 3 =>       Z2 <= '1';  1, 3
                  when 4 to 7 | 2 =>  Z3 <= '1';  2, 4, 5, 6, 7
                  when others =>      Z4 <= '1';  8 . . . 15

                end case;
                ...

\underline{Achtung:} Gerade bei case-Anweisungen wird oft vergessen, daß in allen Fällen eine Signalzuweisung vorkommen muß. Gibt es einen ”Standard-Wert“, so empfiehlt es sich erst eine unbedingte Zuweisung dieses Wertes vor der Verzweigung zu machen (s. obiges Beispiel). Dann brauchen in der Verzweigung nur die davon abweichenden ”Spezialfälle“ behandelt zu werden.

\underline{Beispiel:} 1-aus-4 Decoder

signal DECIN is integer range 0 to 3;
signal D1, D2, D3, D4: bit;
...
P: process
begin

so nicht! — für D1 bis D4 werden FFs synthetisiert

case DECIN is
when 0 => D1 <= '1';
when 1 => D2 <= '1';
when 2 => D3 <= '1';
when 3 => D4 <= '1';
end case;

korrekte Beschreibung — lange Form

case DECIN is
when 0 => D1 <= '1';     D2 <= '0';
          D3 <= '0';     D4 <= '0';
when 1 => D1 <= '0';     D2 <= '1';
          D3 <= '0';     D4 <= '0';
when 2 => D1 <= '0';     D2 <= '0';
          D3 <= '1';     D4 <= '0';
when 3 => D1 <= '0';     D2 <= '0';
          D3 <= '0';     D4 <= '1';
end case;

korrekte Beschreibung — kurze Form

D1 <= '0';                                    default-Zuweisungen

D2 <= '0';
D3 <= '0';
D4 <= '0';
case DECIN is

when 0 => D1 <= '1';  davon abweichende Fälle

when 1 => D2 <= '1';
when 2 => D3 <= '1';
when 3 => D4 <= '1';
end case;

Variablen : Als Zwischenspeicher bei der sequentiellen Abarbeitung einer Aktivierung des Prozesses, entsprechen sie in ihrer Wirkung logischen Ausdrücken und werden auch bei der Synthese so behandelt. Entscheidend ist dabei, daß die Variablen vor jeder Leseoperation Werte zugewiesen bekommen.

\underline{Beispiel:} P: process
           variable TMP: bit;
         begin

...  kein Lesezugriff auf TMP
TMP := (A and B) or C;  gemeinsamer Teilausdruck

           ...
           Y <= D and TMP;
           Z <= (E or TMP) and F;
           ...

2. Schaltwerke ⇔ implizite Register werden eingefügt

Signale : Ist die Signalzuweisung an eine Bedingung der (sequentiellen) Prozeßabarbeitung gekoppelt, so werden speichernde Elemente als Register für Ausgangssignale erzeugt. Abhängig von der Art der Bedingung werden die unterschiedlichen Registertypen ausgewählt.

Zeitverhalten : Taktpegel- oder taktflankengesteuerte Elemente werden durch die Aktivierung im Prozeß unterschieden. Bei flankengesteuerten Elementen können dabei sowohl wait-Anweisungen als auch die sensitivity list eines Prozesses zusammen mit einer if-Anweisung benutzt werden.

\underline{Schema:} process
         begin
           wait until edge;
           ...
         end process;

— oder —

process (sensitivity list)

         begin
           if edge then
             ...
           end if;
         end process;

Dabei können für den Ausdruck edge folgende Bedingungen eingesetzt werden:

\underline{Schema:} nach wait-Anweisung

sig name = '1'  Vorderflanke
sig name = '0'  Rückflanke

in if-Abfrage

sig name'event and sig name = '1'  Vorderflanke

                not sig name'stable and sig name = '1'

sig name'event and sig name = '0'  Rückflanke

                not sig name'stable and sig name = '0'

Kontrollverhalten : Sind mehrere steuernde Signale vorhanden, so bestimmt die Schachtelung der einzelnen Abfragen, ob es sich um synchron oder asynchron wirkende Leitungen handelt (s. Beispiele).

Variablen : Bei der Benutzung als Speicher für Werte über mehrere Aktivierungen des Prozesses hinweg, werden für Variablen implizite Register erzeugt. Dies ist immer dann der Fall, wenn es Pfade in der sequentiellen Abarbeitung Prozesses gibt, auf denen die Variablen als Operanden gelesen werden, ohne daß vorher Zuweisungen ausgeführt wurden. Hinsichtlich der Art der erzeugten Register gelten die oben bei den Signalen beschriebenen Regeln.

Die Unterscheidung, wann Signale und wann Variablen für implizite Register benutzt werden, ergibt sich im allgemeinen aus der Art der Beschreibungsform. Wird der gesamte Speicher außerhalb des Prozesses sichtbar, so sollten die dazugehörigen Signale direkt benutzt werden. Ist dies nicht der Fall, wie beispielsweise bei Schieberegistern (s. Beispiel: parametrisierbares Schieberegister), so müssen notwendigerweise Variablen benutzt werden.

Bei der Beschreibung impliziter Register sollte innerhalb eines Prozesses nur eine Art von speicherndem Element, bezüglich Zeit- und Kontrollverhalten beschrieben werden, da man so die bestmögliche Kontrolle über die Art der erzeugten Elemente hat. Nachfolgend sind die verschiedenen Registertypen exemplarisch vorgestellt:

\underline{Schema:} Latch  LATCH ENABLE: boolean
         process (LATCH ENABLE, D)
         begin
           if LATCH ENABLE then
             Q <= ...
           end if;
         end process;

Latch mit asynchronem Set  SET, LATCH ENABLE: boolean
process (SET, LATCH ENABLE, D)
begin
  if SET then
    Q <= '1';
  elsif LATCH ENABLE then
    Q <= ...
  end if;
end process;
Flipflop  CLK: bit
process (CLK)
begin
  if edge then
    Q <= ...
  end if;
end process;

Flipflop mit asynchronem Reset RESET, CLK: bit

process (RESET, CLK)
begin
  if (RESET = '1') then
    Q <= '0';
  elsif edge then
    Q <= ...
  end if;
end process;

Flipflop mit synchronem Reset RESET, CLK: bit

process (RESET, CLK)
begin
  if edge then
    if (RESET = '1') then
      Q <= '0';
    else
      Q <= ...
    end if;
  end if;
end process;

Durch generische Werte (generic) können Register beschreiben werden, die hinsichtlich der Bitbreite parametrisierbar sind.

\underline{Beispiel:} entity SREG N is  n-bit Schieberegister

generic (REG LEN: integer := 16);  Länge

port( CLK:      in std logic;
      SER IN:   in std logic;
      SER OUT:  out std logic);
end SREG N;
architecture BEHAV of SREG N is
begin
process (CLK)

  variable VALUE: std logic vector(REG LEN-1 downto 0);  Speicher

begin
  if (CLK = '1') and CLK'event then

    VALUE := SER IN & VALUE(REG LEN-1 downto 1);  shift down
    SER OUT <= VALUE(0);  Ausgangsleitung

  end if;
end process;
end BEHAV;

Bei der Beschreibung von flankengesteuerten Registern gelten die folgenden Einschränkungen, um die Synthetisierbarkeit des VHDL-Codes zu gewährleisten:^{12}

Lesezugriff auf Variablen : nach einer Zuweisung darf kein Lesezugriff auf die Variable mehr stattfinden. Diese Bedingung ergibt sich aus der (zeitlich) unterschiedlichen Wirksamkeit der Zuweisung an Variablen (⇒ sofort) und Signale (⇒ erst bei nächster wait-Anweisung).

\underline{Beispiel:} process (CLK)
     variable EDGE VAR, ANY VAR: BIT;
   begin
     if (CLK'event and CLK = '1') then

EDGE VAR  := Y;  Variablenzuweisung
ANY VAR   := EDGE VAR;  erlaubt, da innerhalb der Bedingung

       ...
     end if;

     ANY VAR := EDGE VAR;  Fehler!

     ...
   end process;

12Anmerkung: Die den Takt betreffenden Fälle modellieren Schaltungen die in einem guten Design ohnehin zu vermeiden sind!

nur einen Takt : die Benutzung mehrerer Ausdrücke für Taktflanken innerhalb eines Prozesses ist nicht erlaubt auch wenn diese unabhängig voneinander auf verschiedene Signale / Variablen wirken. Die Auswahl mehrerer Takte für ein Ziel der Zuweisung – explizit durch Multiplexstrukturen oder implizit durch die Schachtelung von Bedingungen – ist nicht synthesefähig und kann höchstens durch externe Logik modelliert werden.

\underline{Beispiel:} zwei in einem Prozeß beschriebene Flipflops

         process(CLK 1, CLK 2)
         begin

           if (CLK 1'event and CLK 1 = '1') then  erste Clock

             Q1 <= B;
           end if;
           ...

           if (CLK 2'event and CLK 2 = '1') then  Fehler!

             Q2 <= B;
           end if;
         end process;

keine Ausdrücke : logische Verknüpfungen anderer Signale mit dem Takt, beispielsweise für Taktausblendungen, sind nicht zulässig. Sie müssen entweder durch externe Beschreibungen oder übergeordnete Bedingungen erreicht werden.

\underline{Beispiel:} if not(CLK'event and CLK = '1') then  Fehler!
         if (CLK ENA = '1' and (CLK'event and CLK = '1')) then  Fehler!

keine Zuweisung bei negierter Flankenbedingung : die Zuweisung im false-Zweig einer durch den Takt bedingten Verzweigung ist nicht möglich, da dies eine Hardware voraussetzt, die das Fehlen einer Taktflanke erkennt. Daraus ergibt sich auch, daß bei geschachtelten Bedingungen die Abfrage der Taktflanke die letzte Bedingung sein muß.

\underline{Beispiel:} process(CLK)
         begin
           if (CLK'event and CLK = '1') then
             SIG <= B;
           else

             SIG <= C;  Fehler!

           end if;
         end process;

10.1.3 Endliche Automaten

Für die VHDL-Modellierung endlicher Automaten gibt es die unterschiedlichsten Möglichkeiten, wovon hier exemplarisch eine Methode vorgestellt werden soll, die die beste Kontrolle über die Syntheseergebnisse verspricht.

Die Grundidee hierbei ist, daß innerhalb der beschreibenden Architektur die sequentielle Logik (δ- und λ-Schaltnetze ⇒ Berechnung des Folgezustandes und der Ausgangsfunktion) und die Zeitglieder in den Rückkopplungspfaden (τ-Register ⇒ Synchronisierung der Zustandsübergänge) in getrennten Prozessen beschrieben werden. Die Unterscheidung des Automatenmodells nach Mealy- und Moore-Modellierung betrifft dabei nur die Codierung des Prozesses der die Schaltnetze beschreibt.

\underline{Beispiel:} entity MEALY is  Mealy-Automat

port (X, CLK: in bit;
Z:      out bit);
end;
architecture BEHAVIOR of MEALY is

type STATE TYPE is (S0, S1, S2);  3-Zustände
signal CURRENT STATE:  STATE TYPE;  aktueller Zustand
signal NEXT STATE:     STATE TYPE;  Folgezustand

begin

COMBIN: process(CURRENT STATE, X)  Prozeß für kombinatorische Logik

begin

case CURRENT STATE is  Verzweigung durch CURRENT STATE

when S0 =>
Z <= '0';  Ausgabe '0'
NEXT STATE <= S1;  ∗-Übergang nach S1
when S1 =>
if X = '0' then
Z <= '1';  Ausgabe '1'
NEXT STATE <= S0;             '0'-Übergang nach S0
else
Z <= '0';  Ausgabe '0'
NEXT STATE <= S2;             '1'-Übergang nach S2
end if;
when S2 =>
if X = '0' then
Z <= '0';  Ausgabe '0'
NEXT STATE <= S1;             '0'-Übergang nach S1
else
Z <= '1';  Ausgabe '1'
NEXT STATE <= S0;             '1'-Übergang nach S0
end if;
end case;
end process;

SYNCH: process  Prozeß für synchrone Elemente (Flipflops)

begin

  wait until CLK'event and CLK = '1';  Synchronisation auf Vorderflanke

  CURRENT STATE <= NEXT STATE;
end process;
end BEHAVIOR;

entity MOORE is  Moore-Automat

port (X, CLK: in bit;
      Z:      out bit);
end;
architecture BEHAVIOR of MOORE is

type STATE TYPE is (S0, S1, S2);  3-Zustände
signal CURRENT STATE:  STATE TYPE;  aktueller Zustand
signal NEXT STATE:     STATE TYPE;  Folgezustand

begin

COMBIN: process(CURRENT STATE, X)  Prozeß für kombinatorische Logik

begin

  case CURRENT STATE is  Verzweigung durch CURRENT STATE

  when S0 =>
    Z <= '0';  Ausgabe '0'
    NEXT STATE <= S1;  ∗-Übergang nach S1
  when S1 =>
    Z <= '1';  Ausgabe '1'
    if X = '0' then
      NEXT STATE <= S0;             '0'-Übergang nach S0
    else
      NEXT STATE <= S2;             '1'-Übergang nach S2
    end if;
  when S2 =>
    Z <= '0';  Ausgabe '0'
    if X = '0' then
      NEXT STATE <= S1;             '0'-Übergang nach S1
    else
      NEXT STATE <= S0;             '1'-Übergang nach S0
    end if;
  end case;
end process;

SYNCH: process  Prozeß für synchrone Elemente (Flipflops)

          begin

            wait until CLK'event and CLK = '1';  Synchronisation auf Vorderflanke

            CURRENT STATE <= NEXT STATE;
          end process;
        end BEHAVIOR;

[figure: S1; S0; S2; */0; 1/1; 0/1; 0/0; 1/0; S1/1; S0/0; S2/0; *; 1; 0; 0; 1; Mealy-Automat; Moore-Automat]

10.1.4 Zusätzliche Information

Genauere Beschreibungen der Möglichkeiten und der Funktionsweise der Synopsys Werkzeuge lassen sich am besten mit Hilfe der Online-Manuals nachlesen – Aufruf mit iview –, dabei sind folgende Kapitel in diesem Zusammenhang zu nennen:

Synthesis          VHDL Compiler Reference

                   Design Compiler Family Reference Manual

Application Notes  Flattening and Structuring: A Look at Optimization Strategies

                   Finite State Machines
                   HDL Coding Styles: Sequential Devices

Neben den hier aufgeführten Beispielen, finden sich umfangreiche VHDL Beispiele unter:

$SYNOPSYS/doc/vhdl/examples
$SYNOPSYS/doc/syn/examples/vhdl

A Syntaxbeschreibung

Anmerkung: Der Anhang ist keine vollständige Syntaxbeschreibung von VHDL — hier sei auf das Reference Manual [IEEE94] verwiesen. Dieser Teil ist vielmehr als Hilfe für den, mit den Grundkonzepten der Sprache vertrauten Designer, gedacht: als Nachschlagehilfe bei Fragen zur Syntax und der Anordnung von VHDL-Konstrukten. Dementsprechend sind nicht alle Produktionen der Sprache dargestellt — die verbleibenden Bezeichner sollten aber für sich sprechen —, dafür wurde Wert darauf gelegt zu zeigen wo welche VHDL-Anweisungen im Code stehen können.

Der Index am Ende dieser Beschreibung ist dient als Cross-Index für die nachfolgenden Syntaxbeschreibungen. Dort sind Verweise für die gängigen Symbole und Bezeichner vorhanden — ständig benutzte Terminale wie begin, end, is usw. sind nicht aufgeführt.

A.1 Übersicht

Da der Aufbau einiger VHDL-Konstrukte aus den Syntaxbeschreibungen nicht klar erkenntlich ist, folgen hier noch einige Diagramme: VHDL-Entwurf : Ein gesamter Entwurf besteht üblicherweise aus einer Anzahl von Da-

teien, die wiederum die analysierbaren Einheiten enthalten.

VHDL-Entwurf analysierbare VHDL-Datei Entity Architektur Package Konfiguration  -Implementation von Entwürfen -Interfacebeschreibung von Entwürfen -allgemeine Deklarationen -Zuordnung von Architekturen zu Entity / Komponente / Instanz

Architekturen : beschreiben die Funktion eines Entity. Sie bestehen aus einem Teil für lokale Deklarationen und einem Anweisungsteil, der konkurrente Anweisungen beinhaltet. Diese können in beliebiger Reihenfolge im VHDL-Code stehen.

Architektur Blöcke Signalzuweisungen Prozeduraufrufe Komponenteninstanziierungen Prozesse  -Gruppierung konkurrenter Anweisungen -Werteberechnung und -zuweisung -Aufruf von Algorithmen, die Werte Signalen zuweisen -Hierarchische Verbindung -Definition sequentieller Algorithmen, die Signalwerte verarbeiten und die Ergebnisse Signalen zuweisen Komponenten Unterprogramme Typen Konstanten Signale 1. Deklarationen 2. konkurrente Anweisungen

Packages : fassen Deklarationen zusammen, die an mehreren Stellen im Entwurf gebraucht werden (insbesondere in mehreren Dateien).

Typen Konstanten Komponenten Unterprogramme Deklarationen Package

Prozesse und Unterprogramme : dienen der Verhaltensbeschreibung durch einen sequentiellen Ablauf von Anweisungen.

Prozesse verarbeiten die Werte von Signalen und weisen ihnen neue Werte zu. Signalzuweisungen werden außerhalb der sequentiellen Abarbeitung wirksam. Die Synchronisation zwischen der Abarbeitung der Anweisungen und dem Verlauf an simulierter Zeit geschieht durch besondere Anweisungen (sensitivity-list, wait).

Unterprogramme strukturieren Verhaltensbeschreibungen und können nur innerhalb von sequentiellen Anweisungen benutzt werden. Signalein- und Ausgaben sind nur nach expliziter Deklaration im Interface möglich.

Unterprogramme Typen Konstanten Prozeß / Unterprogramm Variablen Prozeduraufrufe Statements Variablenzuweisungen Signalzuweisungen If Case Loop Next Exit Null Return -nur bei Unterprogrammen- Wait 1. Deklarationen 2. sequentielle Anweisungen

A.2 Bibliothekseinheiten

entity declaration

entity ENT is begin ....... end ENT;                          package PKG is end PKG;                          package body PKG is end PKG; architecture ARC of ENT is begin ....... end ARC;                                                 configuration CONF of ENT is end CONF; B: block begin ....... end block B;                      P: process begin ....... end process P;                    procedure P (...) is begin ....... end P; entity identifier is [generics] [ports] [entity declarative part] [begin entity statement part] end [identifier];

74 architecture body

entity ENT is begin ....... end ENT;                          package PKG is end PKG;                          package body PKG is end PKG; architecture ARC of ENT is begin ....... end ARC;                                                 configuration CONF of ENT is end CONF; B: block begin ....... end block B;                      P: process begin ....... end process P;                    procedure P (...) is begin ....... end P; architecture identifier of entity name is architecture declarative part begin concurrent statements end [identifier];

package declaration

entity ENT is begin ....... end ENT;                          package PKG is end PKG;                          package body PKG is end PKG; architecture ARC of ENT is begin ....... end ARC;                                                 configuration CONF of ENT is end CONF; B: block begin ....... end block B;                      P: process begin ....... end process P;                    procedure P (...) is begin ....... end P; package identifier is package declarative part end [identifier];

package body

entity ENT is begin ....... end ENT;                          package PKG is end PKG;                          package body PKG is end PKG; architecture ARC of ENT is begin ....... end ARC;                                                 configuration CONF of ENT is end CONF; B: block begin ....... end block B;                      P: process begin ....... end process P;                    procedure P (...) is begin ....... end P; package body identifier is package body declarative part end [identifier];

configuration declaration

entity ENT is begin ....... end ENT;                          package PKG is end PKG;                          package body PKG is end PKG; architecture ARC of ENT is begin ....... end ARC;                                                 configuration CONF of ENT is end CONF; B: block begin ....... end block B;                      P: process begin ....... end process P;                    procedure P (...) is begin ....... end P; configuration identifier of entity name is configuration declarative part block configuration end [identifier];

A.3 Deklarationen

generic declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; generic (identifier list : type [:= expression];; {identifier list : type [:= expression];} );]

79 port declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; port (identifier list : in|out|inout|buffer type [:= expression];; {identifier list : in|out|inout|buffer type [:= expression];} );]

type declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; type identifier is type definition;; – or – incomplete type declaration; type identifier;]

subtype declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; subtype identifier is [resolution function name] type [range expr];]

alias declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; alias identifier : type [(range expr)] is name [(range expr)];]

constant declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; constant identifier : type [range expr] [:= expression];]

variable declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; variable identifier list : type [range expr] [:= expression];]

file declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; file identifier : type is [mode] logical name;]

signal declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; signal identifier list : type [range expr] [:= expression];]

subprogram declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; procedure subprg name [(formal parameter list)];; – or –; function subprg name [(formal parameter list)]; return type;]

subprogram body

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; subprogram specification is; subprogram declarative part; begin; sequential statements; end [subprg name];]

attribute declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; attribute identifier : type;]

component declaration

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; component identifier :; [generic (generic list);]; [port    (port list);]; end component;]

A.4 Spezifikationen

attribute specification

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; attribute attribute name; of entity name; is expression;]

92 configuration specification

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; for label|others|all: component name use; entity [lib name.]entity name(architecture nam e); |; configuration [lib name.]configuration name;; end for;]

disconnection specification

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; disconnect guarded signal specification; after time expr;]

A.5 Bibliotheksbenutzung

library clause

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; library logical name {, logical name};]

95 use clause

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; use selected name {, selected name};]

A.6 sequentielle Anweisungen

wait statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; wait; [on signal name {, signal name}]; [until conditional expr]; [for time expr];]

97 assertion statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; assert condition; [report string expr]; [severity note|warning|error|failure];]

signal assignment statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; target <= [transport] expression [after time expr]; {, expression after time expr}] ;]

variable assignment statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; target := expression;]

procedure call statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; procedure name [(actual parameters)];]

if statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; if condition then; sequential statements; {elsif condition then; sequential statements}; [else; sequential statements]; end if;]

case statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; case expression is; {when value|or val list|val range =¿ sequential statements}; [when others => sequential statements]; end case;]

loop statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; [loop label:]; [while condition |; for loop specification] loop; sequential statements; end loop [loop label];]

next statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; next [loop label]; [when condition];]

exit statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; exit [loop label]; [when condition];]

return statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; return [expression];]

null statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; null;]

A.7 konkurrente Anweisungen

block statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; label: block [(guard expression)]; [generics]; [ports]; [declarations]; begin; concurrent statements; end block [label];]

109 process statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; [label:] process [(sensitivity list)]; process declarative part; begin; sequential statements; end process [label];]

concurrent procedure call

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; [label:] procedure call statement;]

concurrent assertion statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; [label:] assertion statement;]

concurrent signal assignment statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; [label:] target <=; {expression [after time expr] when condition else}; [guarded] expression [after time expr];; – or –; [label:] with expression select; target <= {expression [after time expr] when choices[,]};]

component instantiation statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; label : component name; [generic map (map)]; [port    map (signals)];]

generate statement

[figure: entity ENT is; begin; .......; end ENT;; package PKG is; end PKG;; package body PKG is; end PKG;; architecture ARC of ENT is; begin; .......; end ARC;; configuration CONF of ENT is; end CONF;; B: block; begin; .......; end block B;; P: process; begin; .......; end process P;; procedure P (...) is; begin; .......; end P;; label: for loop parameter specification generate |; label: if condition generate; {concurrent statement}; end generate [label];]

A.8 Vordefinierte Attribute

Attribut  Prefix  Parameter  Ergebnis

auf Typen bezogen:

t'base

Typ/Untertyp t Basistyp zu t, nur als Präfix

anderer Attribute zulässig

t'left

skalarer Typ t linke Grenze von t

t'right

skalarer Typ t rechte Grenze von t

t'low

skalarer Typ t untere Grenze von t

t'high

skalarer Typ t obere Grenze von t

t'pos(x)

diskreter oder physikalischer Typ t Ausdruck: Wert ist in Typ t enthalten

Position von Wert x in t

t'val(x)

diskreter oder physikalischer Typ t

Ausdruck: integer Wert in t: auf Position x

t'succ(x)

diskreter oder physikalischer Typ t Ausdruck: Wert ist in Typ t enthalten Wert in t: Positionsnr. ist eine größer als bei x

t'pred(x)

diskreter oder physikalischer Typ t Ausdruck: Wert ist in Typ t enthalten Wert in t: Positionsnr. ist eine kleiner als bei x

t'leftof(x)

diskreter oder physikalischer Typ t Ausdruck: Wert ist in Typ t enthalten

Wert in t: links von x

t'rightof(x) diskreter oder physikalischer Typ t Ausdruck: Wert ist in Typ t enthalten

Wert in t: rechts von x

auf Arrays bezogen:

a'left[(n)]

Array-Objekt, Alias eines Array oder begrenzter A-Untertyp Ausdruck: integer, innerhalb der Dimensionen von a, Default 1 linke-Grenze des n-ten Index von a

a'right[(n)]

Array-Objekt, Alias eines Array oder begrenzter A-Untertyp Ausdruck: integer, innerhalb der Dimensionen von a, Default 1 rechte-Grenze des n-ten Index von a

a'low[(n)]

Array-Objekt, Alias eines Array oder begrenzter A-Untertyp Ausdruck: integer, innerhalb der Dimensionen von a, Default 1 untere-Grenze des n-ten Index von a

a'high[(n)]

Array-Objekt, Alias eines Array oder begrenzter A-Untertyp Ausdruck: integer, innerhalb der Dimensionen von a, Default 1 obere-Grenze des n-ten Index von a

a'range[(n)]

Array-Objekt, Alias eines Array oder begrenzter A-Untertyp Ausdruck: integer, innerhalb der Dimensionen von a, Default 1 Bereich: n-ter Index entsprechend Deklaration

a'reverse range[(n)] Array-Objekt, Alias eines Array oder begrenzter A-Untertyp Ausdruck: integer, innerhalb der Dimensionen von a, Default 1 umgekehrter Bereich: n-ter Index entspr. Deklaration

a'length[(n)] Array-Objekt, Alias eines Array oder begrenzter A-Untertyp Ausdruck: integer, innerhalb der Dimensionen von a, Default 1 Anzahl der Werte des n-ten Index von a

Attribut  Prefix  Parameter  Ergebnis

auf Signale bezogen:

s'delayed(t)

Signal s Ausdruck: time ≥ 0, Default 0 ns Signal: zu s äquivalent, zeitlich um t verzögert

s'quiet(t)

Signal s Ausdruck: time ≥ 0, Default 0 ns bool-Signal: true –s war die letzten t Zeiteinheiten ruhig

s'stable(t)

Signal s Ausdruck: time ≥ 0, Default 0 ns bool-Signal: true –s hatte t Zeiteinh. keine Wertewechsel

s'transaction

Signal s bit-Signal: Wechsel / toggle –s ist im Sim.zyklus aktiv

s'event

Signal s bool-Wert: true –s hat ein Event

s'active

Signal s bool-Wert: true –s ist im Sim.zyklus aktiv

s'last event

Signal s Zeit seit dem letzten Event von s

s'last active

Signal s Zeit seit letzter Aktivität von s in einem Sim.zyklus

s'last value

Signal s Wert von s vor dem letzten Wertewechsel

Attribut Prefix Parameter Ergebnis

auf Blöcke bezogen:

b'behavior

Block-Label b oder architecture b bool-Wert: true –b instanziiert keine Komponenten

b'structure

Block-Label b oder architecture b bool-Wert: true –b enthält keine Prozesse oder vergl. (nicht passive) Anweisungen

A.9 Reservierte Bezeichner

abs              element          label            package          then
access           else             library          port             to
after            elsif            linkage          postponed        transport
alias            end              literal          private          type
all              entity           loop             procedure
allow            exit                              process          unaffected
and                               map              pure             units
architecture     file             mod                               until
array            for                               range            use
assert           function         nand             record
attribute                         new              register         variable
                 generate         next             reject
begin            generic          nor              rem              wait
block            group            not              report           when
body             guarded          null             return           while
buffer                                             rol              with
bus              if               of               ror
                 impure           on                                xnor
case             in               open             select           xor
component        initial          or               severity
configuration    inout            others           signal
constant         is               out              shared

                                                   sla

disconnect                                         sll
downto                                             sra

                                                   srl
                                                   subtype

Literatur

[Arm88] J. R. Armstrong: Chip-Level Modeling with VHDL, Prentice Hall, Englewood Cliffs, 1988

[Bha92] J. Bhasker: A VHDL Primer, Prentice Hall, Englewood Cliffs, 1992

[Coe89] D. Coelho: The VHDL Handbook, Kluver Academic Publishers, Norwell MA, 1989

[HaEA91] R. E. Harr, et al: Applications of VHDL to Circuit Design, Kluver Academic Publishers, Norwell MA, 1991

[IEEE94] IEEE Standard VHDL Language Reference Manual – Std 1076-1993, IEEE, New York, 1994

[LeSh89] S. Leung, M. Shanblatt: ASIC System Design with VHDL – A Paradigm, Kluver Academic Publishers, Norwell MA, 1989

[LSU89] R. Lipsett, C. Shaefer, C. Ussery: VHDL: Hardware Description and Design, Kluver Academic Publishers, Norwell MA, 1989

[MaLa93] S. Mazor, P. Langstraat: A Guide to VHDL, 2nd edition, Kluver Academic Publishers, Norwell MA, 1993

[Per89] D. Perry: VHDL, McGraw Hill, New York, 1989

[PeTa96] D. Pellerin, D. Taylor: VHDL Made Easy!, Upper Saddle River NJ, Prentice Hall, 1996

Index

:=, 79, 80, 84, 85, 87, 100 <=, 99, 113 =>, 103

after, 94, 99, 113 alias, 83 architecture, 75 assert, 98, 112 attribute, 90, 92

block, 109 body, 77

case, 103 component, 91, 114 configuration, 78 constant, 84

disconnect, 94

else, 102 elsif, 102 entity, 74 exit, 106

file, 86 for, 93, 97, 104, 115 function, 88, 89, 101

generate, 115 generic, 79, 91 guarded, 109, 113

if, 102, 115

library, 95 loop, 104

next, 105 null, 108

on, 97 others, 103 package, 76, 77 port, 80, 91 procedure, 88, 89, 101, 111 process, 110

report, 98 return, 88, 107

select, 113 severity, 98 signal, 87 subtype, 82

then, 102 transport, 99 type, 81

until, 97 use, 93, 96

variable, 85

wait, 97

when, 103, 105, 106, 113 while, 104 with, 113