====== Design Entities und Configurations ====== ===== Entity ===== ==== Beispiele ==== Beispiel für eine Testbench, die keine Ein- oder Ausgänge besitzt. ENTITY testbench IS END testbench ; ---- Entity für einen 2-Bit-Volladdierer. * //X// , //Y// und //Cin// sind Eingänge vom Typ Bit. * //Cout// und //Sum// sind Ausgänge vom Typ Bit. ENTITY fulladder IS PORT (X,Y,Cin : IN Bit; Cout, Sum : OUT Bit); END fulladder ; ---- Entity mit mehreren Features: * Definition eines Parameters //m// . * //b1// und //b2// sind Eingänge (Bits), //b3// ist ein Ausgangsvektor der Breite //m// . * Definition des Typs //byte// als Bitvektor. * Einbinden der Objekte aus dem Package //timing_library// . Definition und Initialisierung einer konstanten Setup-Zeit. Definition der Prozedur //init// mit Signalübergabe. Um //delay// verzögerte Belegung von //b4// mit lauter Einsen. Anweisungen innerhalb der Entity: * Ist die zu überprüfende Bedingung nicht erfüllt, erfolgt eine Fehlermeldung. Sicherheitsstufe ist //Error// . * Aufruf einer passiven //Prozedur// (keine Signalzuweisungen in der Entity erlaubt!) mit //b4// und //delay// als Übergabewerte. ENTITY big_example IS GENERIC (m : Positive); PORT (b1,b2 : IN Bit; b3: OUT Bit_Vector(1 to m)); TYPE byte IS ARRAY (1 TO 8) OF Bit; USE work.timing_library.all; CONSTANT setuptime : Time := 12 ns; PROCEDURE init ( SIGNAL b4: OUT byte) IS BEGIN b4 <= ( OTHERS => '1') AFTER delay; END init; BEGIN ASSERT b4' DELAYED'STABLE (5 ns) REPORT "Error occured!" SEVERITY Error; passive_procedure(b2,delay); END big_example ; ===== Architecture ===== ==== Beispiele ==== Beispiel für eine leere Architecture der Entity //box// . ARCHITECTURE arch OF box IS BEGIN END arch ; ---- Beispiel für eine Architecture der Entity //fulladder// . //A// und //B// sind die benötigten internen Zwischensignale. Im architecture-body stehen mehrere nebenläufige Anweisungen, die die Funktion des Volladdierers beschreiben. ARCHITECTURE rtl OF fulladder IS SIGNAL A,B: Bit ; BEGIN A <= X XOR Y ; B <= A AND Cin ; Sum <= A XOR Cin ; Cout <= B OR (X AND Y) ; END rtl ; ---- Beispiel für zwei verschiedene Architectures für die Entity //entity1// . //rtl1// : Definition der benötigten Konstante delay und des Zwischensignals //S// . Zwei nebenläfige Signalzuweisungen mit Zeitverzögerungen und dem Aufruf der Funktion //czbit// . ARCHITECTURE rtl1 OF entity1 IS CONSTANT delay: Time :=5 ns; SIGNAL S: Bit; BEGIN S2 <= czbit(S) AFTER 3 ns ; S <= S1 AFTER delay ; END rtl1 ; ---- //rtl2// : Definition und Initialisierung des Zwischensignals //S// . Definition der Procedure //proc// mit Signalübergabe von //A// und //B// . Bedingte Signalzuweisung an //B// . Drei nebenläufige Anweisungen mit Namen //P1// , //P2// und //P3// . * //P1// ist ein Prozeduraufruf. * //P2// ist eine Signalzuweiung durch Aufruf einer Funktion. * //P3// ist ein Prozeß, in dem die Variable //V// deklariert und dieser der Wert von //S// zugewiesen wird. ARCHITECTURE rtl2 OF entity1 IS SIGNAL S: Bit :='1' ; PROCEDURE proc( SIGNAL A: IN Bit SIGNAL B: INOUT Bit) IS BEGIN B <= NOT B WHEN A ='1' ELSE B ; END proc ; BEGIN P1: proc(S1,S); P2: S2 <= czbit(S) AFTER 2 ns ; P3: PROCESS (S) VARIABLE V :Bit ; BEGIN V := S ; END PROCESS P3; END rtl2 ; ===== Configuration ===== ==== Beispiele ==== Beispiel für eine Default-Configuration einer Testbench, die für die Architecture //arch_of_testbench// das entsprechende analysierte Objekt verwendet. CONFIGURATION cfg OF testbench IS FOR arch_of_testbench END FOR ; END cfg ; ---- Die Bibliotheken //vendor// und //mylib// werden bekanntgemacht. Für die Entity //example// wird alles aus der Bibliothek //mylib// bekanntgemacht und in ihrer Architecture //structural// werden für die Instanz //ALU// mit dem Label //ALU1// die Entity //alu_ver_2// mit der Architecture //beh// aus der Bibliothek //mylib// , für die Instanzen von //MUX// unter den Labeln //mux1// , //mux2// und //mux3// die Entity //mux12345// mit der Architecture //rtl// aus der Bibliothek //vendor// und für alle Instanzen von //add// die Defaults verwendet. LIBRARY vendor, mylib ; CONFIGURATION cfg_of_ex OF example IS USE mylib.ALL ; FOR structural FOR ALU1: ALU USE ENTITY mylib.alu_ver_2(beh); END FOR ; FOR mux1, mux2, mux3: MUX USE ENTITY vendor.mux12345(rtl); END FOR ; FOR ALL : add END FOR ; END FOR ; END cfg_of_ex ; ====== Unterprogramme und Packages ====== ===== Unterprogrammdeklaration ===== ==== Anmerkung ==== Reine (pure) Funktionen liefern bei mehreren Aufrufen mit den gleichen actual parameters die gleichen Rückgabewerte. Unreine (impure) Funktionen können bei mehreren Aufrufen mit den gleichen actual parameters unterschiedliche Rückgabewerte liefern. Dies ist z.B. der Fall wenn die unreine Funktion Files ausliest, deren Inhalt sich während der Simulatin ändern. ==== Beispiele ==== Einfache Deklaration der Prozedur //thank_you// ohne Übergabewerte PROCEDURE thank_you ; ---- Declaration of the procedure //test// with the transfer value //A// . PROCEDURE test( A : Bit ) ; ---- Deklaration der Funktion //convert// mit //B// als Übergabewert und //fuzzy_bit// als Ergebnistyp. FUNCTION convert( B : Bit ) RETURN fuzzy_bit ; ---- Deklaration der Prozedur //regist// mit Übergabe der Signal //D// , //CK// und //Q// . PROCEDURE regist( SIGNAL D : IN Bit; SIGNAL CK : IN Bit; SIGNAL Q : OUT Bit ) ; ---- Deklaration der Prozedur //p// mit Übergabe der Variablen //COL// und der Konstanten //C// . PROCEDURE p( VARIABLE COL : INOUT color; CONSTANT C : IN choice ) ; ===== Der Body eines Unterprogramms ===== ==== Anmerkungen ==== * Die Deklaration eines Unterprogrammes ist optional. Die Unterprogrammdefinition kann als Deklaration angesehen werden. * In Unterprogrammen sind Deklarationen von //shared variables// verboten. * Ein "fremdes Unterprogramm" ist ein Unterprogramm, das mit dem Attribut **FOREIGN** versehen ist. Der Wert des Attributes (ein String) kann z.B. implementierungsspezifische Angaben zur Anbindung eines externen Programms enthalten (siehe Beispiel unten). * Eine reine Funktion darf keine Referenz zu einem explizit deklarierten Fileobjekt beinhalten. * Eine reine Funktion darf nicht Elternteil einer unreinen Funktion sein. ==== Beispiele ==== Definition der Prozedur //thank_you// . Ist die Bedingung //false// nicht erfüllt, wird die Meldung "Thank You !" ausgegeben, da die Sicherheitsstufe //note// ist. PROCEDURE thank_you IS BEGIN ASSERT false REPORT "Thank You !" SEVERITY note ; END thank_you ; ---- Definition der Funktion //convert// mit Übergabewert //B// und Ergebnistyp //fuzzy_bit// . In der If-Schleife wird der Variable //v// abhängig vom Wert von //B// der Wert High oder Low zugewiesen. Als Rückgabewert wird //v// übergeben. FUNCTION convert(B : Bit ) RETURN fuzzy_bit IS VARIABLE v : fuzzy_bit ; BEGIN IF B = '1' THEN v := High ; ELSE v := Low ; END IF ; RETURN v ; END convert ; ---- Definition der Prozedur //regist// mit den Übergabewerten der Signale //D// , //CK// und //Q// . In der Endlosschleife (LOOP) wird ein Register deklariert, das mit der positiven Taktflanke den Wert vom Eingang //D// am Ausgang //Q// mit einer Verzögerung von 1 ns übernimmt. PROCEDURE regist( SIGNAL D : IN Bit ; SIGNAL CK : IN Bit ; SIGNAL Q : OUT Bit ) IS BEGIN LOOP WAIT ON CK ; IF CK = '1' THEN Q <= D AFTER 1 ns ; END IF ; END LOOP ; END regist ; ---- Definition der Prozedur //p// mit den Übergabewerten der Variable //COL// und der Konstante //C// . Es wird der Untertyp //primary_color// aus dem Typ //color// deklariert, mit dem Bereich (aus dem Aufzälungstyp //color// ) von //yellow// bis //red// . Es werden die Variablen //X// , //Y// und //Z// deklariert. PROCEDURE p( VARIABLE COL : INOUT color ; CONSTANT C : IN choice ) IS SUBTYPE primary_color IS color RANGE yellow TO red ; VARIABLE X, Y, Z : primary_color ; BEGIN ... ... END p ; ---- Die extern vorliegende Funktion //exfunc// wird deklariert. Das Attribut //FOREIGN// für //exfunc// wird mit (Simulator-)programmspezifischen Daten belegt. FUNCTION exfunc RETURN INTEGER ; ATTRIBUTE FOREIGN OF exfunc FUNCTION IS "C:modellib.so.0.1 ELAB:mod_lab"; ===== Überladen ===== ==== Überladen von Unterprogrammen ==== Verschiedene Unterprogramme mit gleichem Namen, aber mit unterschiedlichem Verhalten, werden wie gewöhnlich deklariert. Dies gilt gleichermaßen für Prozeduren und Funktionen. Nach folgenden Kritierien muß genau eine Prozedur oder Funktion gewählt werden können ([[.:use-statements#overloading_resolution|Auflösung von Überladungen]]): * Zahl der Argumente * Typen der Argumente * Namen der Argumente (bei Argumentübergabe durch explizite Namensnennung "named association", s.Bsp.) * Typ des Rückgabewertes Besitzen bei einem Funktionsaufruf mehrere Varianten Gültigkeit, so verbirgt die lokale Variante (z.B. im Deklarationsteil der Architektur) die hierarchisch höher deklarierte Variante (z.B. aus einem Package). Mit vollständiger hierarchischer Angabe des Unterprogrammnamens kann trotzdem auf jede gewünschte Variante zugegriffen werden ([[.:Qualified Expression]]). ==== Überladen von Operatoren ==== Operatoren unterscheiden sich von einfachen Funktionen in zwei Punkten: * Der Name bzw. das Symbol von Operatoren gilt nicht als "normaler" Bezeichner, sondern ist eine Zeichenkette (String) und steht deshalb bei der Deklaration in Anführungsstrichen. * Die Operanden stehen beim üblichen Aufruf eines Operators vor bzw. nach dem Operator (bei unären Operatoren nur danach) und nicht in nachgestellten runden Klammern. Operatoren können aber auch in der Syntax normaler Funtionsaufrufe angesprochen werden (s.Bsp.). Die Handhabung von Operatoren als String ist bei der Deklaration von überladenen Operatoren zu beachten. Ansonsten entspricht diese dem Überladen von Funktionen und Prozeduren. ==== Beispiele ==== In den Beispielen werden nur die Deklarationen und die Aufrufe der überladenen Unterprogramme gezeigt. Zu jeder Deklaration muß natürlich eine Definition des Unterprogrammes geschrieben werden. ---- Es werden zwei Prozeduren //write// deklariert, wobei der Übergabewert //value// einmal als Integer und einmal als String deklariert wird. Beim Aufruf der Prozeduren wird durch den Typ des jeweiligen zweiten Übergabewertes bestimmt, welche Prozedur zu verwenden ist. PROCEDURE write ( F : INOUT Text ; value : Integer ) ; PROCEDURE write ( F : INOUT Text ; value : String ) ; write (sys_error, "Unexpected output"); write (sys_output, 12) ; ---- Es werden zwei Prozeduren //check// deklariert. Sie unterscheiden sich einerseits im Namen des ersten Übergabewertes und andererseits in der Reihenfolge der Definition der zwei Signale //C// und //D// . Bei den ersten beiden Prozedur-Aufrufen wird durch den Namen des ersten Übergabewertes bestimmt, welche Prozedur zu verwenden ist. Sind die Typen //Data// und //Clock// identisch, ist der dritte Aufruf nicht eindeutig und damit verboten. PROCEDURE check ( setup : Time ; SIGNAL D : Data ; SIGNAL C : Clock ) ; PROCEDURE check ( hold : Time ; SIGNAL C : Clock ; SIGNAL D : Data ) ; check ( setup => 10 ns, D => D_Bus, C => Clk_1 ) ; check ( hold => 5 ns, D => D_Bus, C => Clk_2 ) ; check ( 15 ns, D_Bus, Clk ) ; ---- Nach der Definition des Typs //mvl// werden die Standardoperatoren //AND// , //OR// und //NOT// überladen. Als übergabe- und Ergebniswerte wird hier jeweils der Typ //mvl// verwendet. Die Signalzuweisungen an //Q// , //R// und //S// zeigen die Verwendung der überladenen Operatoren. Interessant ist der zweite Aufruf, bei dem der Operator explizit als Funktion aufgerufen wird und die Operanden als Übergabewerte dienen. TYPE mvl IS ( '0', '1', 'Z', 'X' ) ; FUNCTION "AND" (L, R : mvl) RETURN mvl; FUNCTION "OR" ( L, R : mvl ) RETURN mvl ; FUNCTION "NOT" ( R : mvl ) RETURN mvl ; SIGNAL Q, R, S : mvl ; Q <= 'X' OR '1' ; R <= " OR "( '0', 'Z' ) ; S <= ( Q AND R ) OR NOT S ; ===== Auflösungsfunktion ===== ==== Definition ==== Eine Resolution Function (Auflösungsfunktion) bestimmt den Wert eines Signals, wenn an dieses Signal gleichzeitig durch mehr als eine Quelle Zuweisungen erfolgen. Notwendig wird dies z.B., wenn folgende nebenläufige Zuweisungen an das **unresolved** Signal Z existieren: Z <= A; Z <= B; Exisitert für Z keine Resolution Function, so ist nicht geklärt, welchen Wert Z erhält, wenn A='0' und B='1' gilt. Die Verbindung zwischen Signal und einer Resolution Function wird in der [[.:Signal declarations|Signaldeklaration]] hergestellt. Es ist auch möglich, einen [[.:Subtype declarations|Subtype]] zu deklarieren, der einen Typ mit einer Resolution Function verbindet. ==== Beispiel ==== Es wird eine //Resolution Function// deklariert, die mehrfache Signalzuweisungen nach dem Prinzip des //wired_or// auflöst. Die Konstante //floatvalue// wird als //Bit// deklariert und mit '0' initialisiert. Treibt keine Quelle ein Signal ( //inputs'Length// = 0) wird der Wert von //floatvalue// , also '0' übergeben. Treibt einer der Eingänge eine '1', so wird der Wert '1' zurückgegeben, ansonsten '0'. FUNCTION wired_or ( inputs : Bit_vector ) RETURN Bit IS CONSTANT floatvalue : Bit := '0' ; BEGIN IF inputs'Length = 0 THEN RETURN floatvalue ; ELSE FOR i IN inputs'Range LOOP IF inputs(i) = '1' THEN RETURN '1' ; END IF ; END LOOP ; RETURN '0' ; END IF ; END ; ===== Packagedeklaration ===== ==== Beispiele ==== Deklaration des Packages //pck// , in dem die Integer-Konstante //CINT// deklariert wird. PACKAGE pck IS CONSTANT CINT : integer; END pck; ---- Deklaration des Packages //tristate// , in dem der Aufzählungstyp //Tri// deklariert und drei Funktionen ( //BitVal// , //TriVal// , //Resolve// ) mit entsprechenden Übergabewerten und Ergebnistypen deklariert werden. Weiterhin wird ein Typ //TriVector// als Vektor des Typs //Tri// und der maximalen Länge ( //NATURAL RANGE// <> ) deklariert. PACKAGE tristate IS TYPE Tri IS ('0', '1', 'Z', 'E'); FUNCTION BitVal (Value : Tri) RETURN Bit; FUNCTION TriVal (Value : Bit) RETURN Tri; TYPE TriVector IS ARRAY ( NATURAL RANGE <>) OF Tri; FUNCTION Resolve (Sources : TriVector) RETURN Tri; END tristate; ---- Es werden die Objekte der Bibliothek //parts// eingebunden. Das Signal //S// wird als //guarded signal// (BUS) deklariert und mit dem Wert 1 initialisiert. Der/Die Treiber für das Signal //S// wird/werden nicht sofort nach Deaktivierung von //S// getrennt, sondern erst 2 ns später. Es werden die zwei Components //latch// und //clock// mit entsprechenden Ein- und Ausgängen deklariert. Die Component //latch// beinhaltet dabei noch einen Generic //N// . PACKAGE pck_2 IS USE work.parts.all; SIGNAL S : resol_bit BUS := '1'; DISCONNECT S AFTER 2 ns; COMPONENT latch GENERIC (C : Natural); PORT (A : IN Bit; B : OUT Bit_vector (1 TO C)); END COMPONENT ; COMPONENT clock PORT (CK : OUT Bit); END COMPONENT ; END pck_2; ===== Der Body eines Packages ===== ==== Beispiele ==== Die Objekte der Bibliothek //pck_0// werden eingebunden. Im Package Body wird die Konstante //cint// , die schon im Package-Kopf deklariert sein muß, nochmals als Integer deklariert und mit dem Ergebniswert aus dem Funktionsaufruf f(6) initialisiert. ([[.:Constant declarations|deferred constant]]) USE work.pck_0.all; PACKAGE BODY pck IS CONSTANT cint : integer := f(6); END pck ; ---- Definition des Package Bodys //pck_1// , in dem die zwei Funktionen //G// und //F// deklariert werden. In der Funktion //G// wird als Ergebnis der Wert der Gleichung //A XOR B// als Bit zurückgegeben. In der Funktion //F// wird eine Variable //V// als Bit deklariert, der der Wert aus //S1 NAND S2// übergeben wird. Als Ergebniswert liefert die Funktion //F// den Bit-Wert, der sich aus dem Funktionsaufruf //G(V, S2)// ergibt. PACKAGE BODY pck_1 IS FUNCTION G ( A, B : Bit ) RETURN Bit IS BEGIN RETURN NOT ( A XOR B ); END ; FUNCTION F ( S1, S2 : Bit ) RETURN Bit IS VARIABLE V : Bit; BEGIN V := S1 NAND S2; RETURN G(V, S2); END ; END pck_1 ; ---- Definition des Package Bodys //tristate// , in dem die zwei Funktionen //BitVal// und //TriVal// deklariert werden. In der Funktion //BitVal// wird eine Konstante //Bits// deklariert und mit dem Wert "0100" initialiasiert. Als Ergebnis wird hier der Wert des Bits an der Stelle //Tri'Pos ( Value )// von //Bits// zurügegeben. In der Funktion //TriVal// wird eine Variable //V// vom Typ //Tri// deklariert und mit dem Wert //Z// initialisiert. In der **LOOP**-Schleife wird in Abhängigkeit vom jeweiligen Wert von //Source(i)// und //V// entweder der Wert von //Source(i)// an //V// übergeben oder //E// als Ergebniswert zurückgegeben. Für ersteren Fall wird anschließend //V// als Ergebniswert zurückgegeben. PACKAGE BODY tristate IS FUNCTION BitVal ( Value : Tri ) RETURN Bit IS CONSTANT Bits : Bit_Vector := "0100"; BEGIN RETURN Bits(Tri'Pos(Value)) END ; FUNCTION TriVal ( Value : Bit ) RETURN Tri IS VARIABLE V : Tri := 'Z'; BEGIN FOR i IN Sources'Range LOOP IF Sources(i) /= 'Z' THEN IF V = 'Z' THEN V := Sources(i); ELSE RETURN 'E'; END IF ; END IF ; END LOOP ; RETURN V ; END ; END tristate ; ===== Konformitätsregeln ===== ==== Definition ==== Falls die Sprach-Regeln eine Mehrfach-Spezifikation eines Unterprogrammes benötigen oder erlauben, so sind folgende Variationen erlaubt: * Eine numerische Variable kann nur genau dann durch eine andere numerische Variable ersetzt werden, wenn beide den gleichen Wert besitzen. * Ein einfacher Name kann nur genau dann durch einen selektierten Namen, innerhalb dessen der einfache Namen den Selektor darstellt, ersetzt werden, wenn in beiden Spezifikationen der Sinn des einfachen Namens durch die selbe Deklaration festgelegt wird. Zwei Spezifikationen von einem Unterprogramm sind //konform// , wenn, abgesehen von Kommentaren und den oben erwähnten Variation, beide Spezifikationen aus der selben Abfolge von lexikalischen Elementen gebildet werden und korrespondierende lexikalische Elemente die selbe Bedeutung haben. Die Spezifikation einer unreinen Funktion ist niemals konform zu der einer reinen Funktion. ==== Beispiele ==== Die Spezifikationen der Prozedur p sind nicht konform, da diese nicht aus der selben Abfolge von lexikalischen Elementen gebildet werden. PROCEDURE p ( x, y : integer ); PROCEDURE p (x : integer ; y : integer); PROCEDURE p ( x, y : IN integer ); ====== Typen ====== ===== Skalare Typen ===== ==== Beispiele ==== Es werden unterschiedliche Typen deklariert. * Die Typen //Bit// und //switch_level// sind als Aufzählungstypen über Characters deklariert und können nur die Werte //0// oder //1// bzw. //X// annehmen. Diese //0// und //1// sind von den Integerwerten //0// und //1// zu unterscheiden. Diese beiden Zeichen sind dann [[.:use-statements#overloading_resolution|überladen]]. * Die Typen //states// und //colors// sind als Aufzählungstypen über selbstsprechende Elementennamen deklariert. TYPE Bit IS ( '0', '1' ) ; TYPE switch_level IS ( '0', '1', 'X' ) ; TYPE states IS (out, sleeping, working); TYPE colors IS ( red, green, blue ); ---- * Integertypen werden durch die Angabe von ganzen Zahlen bei der Bereichsangabe (RANGE) erzwungen. * Der Bereich kann aufsteigend (TO) oder abfallend (DOWNTO) deklariert werden. * Reelle Typen werden durch reelle Bereichsangaben erzwungen. * Subtypes können durch die Angabe des Basistyps und des ausgewählten Bereiches deklariert werden. TYPE byte_length_integer IS RANGE 0 TO 255 ; TYPE word_index IS RANGE 31 DOWNTO 0 ; TYPE my_real IS RANGE 0.0 TO 9.99 ; SUBTYPE high_bit_low IS byte_length_integer RANGE 0 TO 127 ; ---- Bei physikalischen Typen wird zuerst ein Real-Typ definiert. Anschließend wird die Basiseinheit und die daraus abgeleiteten Einheiten deklariert. Als Beipiele sind hier die Definitionen der Längeneinheiten ( //distance// ) und der Zeiteinheiten ( //time// ) gezeigt. Die physikalische Einheit //time// ist ein vordefinierter Typ. TYPE distance IS RANGE 0 TO 1E16 UNITS -- Basiseinheit : A -- Angström -- Metrische Einheiten : nm = 10 A ; -- Nanometer um = 1000 nm ; -- Mikrometer mm = 1000 um ; -- Millimeter cm = 10 mm ; -- Centimeter m = 1000 mm ; -- Meter km = 1000 m ; -- Kilometer END UNITS ; TYPE time IS RANGE -1E18 TO 1E18 UNITS fs ; --Femtosekunde ps = 1000 fs ; -- Picosecond ns = 1000 ps ; -- Nanosecond us = 1000 ns ; -- Microsecond ms = 1000 us ; -- Millisecond sec = 1000 ms ; -- Second min = 60 sec ; -- Minute END UNITS ===== Zusammengesetzte Typen ===== ==== Beispiele ==== //mt_word// wird als Bitvektor der Breite 32 deklariert, wobei die Indizes von links nach rechts ansteigen. TYPE my_word IS ARRAY ( 0 TO 31 ) OF bit ; ---- //data_in// wird als Vektor des Typs //five_level_logic// und der Breite 8 deklariert, wobei die Indizes von links nach rechts abfallen. TYPE data_in IS ARRAY ( 7 DOWNTO 0 ) OF five_level_logic ---- //memory// wird als Vektor des Typs //my_word// und beliebiger Breite (<>) deklariert. Die Richtung und die maximal mögliche Breite wird durch den Typ //integer// festgelegt. TYPE memory IS ARRAY (integer RANGE <>) OF my_word ; ---- //t// wird als Vektor des Typs //element// und der Breite 1+( //max - min// ) vom Typ //positiv// deklariert. TYPE t IS ARRAY (positive RANGE min TO max) OF element; ---- //date// wird als Record deklariert, welches aus den Elementen //day// , //month// und //year// besteht. TYPE date IS RECORD day : integer RANGE 1 TO 31; month : month_name; year : integer RANGE 0 TO 2100; END RECORD ; ===== Zeiger-Typen ===== ==== Definitionen ==== === access_type_definition === ''access [[.:bnf#subtype_indication]]'' Durch die Deklaration eines Access Type wird ein Zeigertyp deklariert, der für eine spätere Deklaration einer Zeigervariablen verwendet werden kann. === incomplete_type_declaration === ''type [[.:bnf#identifier]]'' Durch eine unvollständige Typ-Deklaration wird eine Modellierung von rekursiven Strukturen möglich. Die vollständige Typ-Deklaration muß noch im gleichen Deklarationsbereich erfolgen. ==== Examples ==== Es werden die Zeigertypen //address// und //buffer_ptr// deklariert. Zieltypen sind //memory// und //buffer// . TYPE address IS ACCESS memory ; TYPE buffer_ptr IS ACCESS buffer ; ---- Es wird eine rekursive Struktur aufgebaut. Zunächst wird der Typ //cell// unvollständig deklariert. Daraufhin wird der Zeigertyp //link// auf den Typ //cell// deklariert. Anschließend wird der Typ //cell// vollständig als Record deklariert. Die Elemente //succ// und //pred// werden als Zeigertypen deklariert. Dadurch kann eine verkettete Liste aufgebaut werden, bei der jedes Element einen Zeiger auf seinen Vorgänger und auf seinen Nachfolger enthält. TYPE cell ; TYPE link IS ACCESS cell ; TYPE cell IS RECORD value : integer ; succ : link ; pred : link ; END RECORD ; ===== Datei-Typen ===== ==== Beispiele ==== Es werden die zwei Filetypen //string_file// und //natural_file// deklariert. Sie sollen Elemente des Typs //string// und //natural// enthalten. TYPE string_file IS FILE OF string TYPE natural_file IS FILE OF natural ---- Es wird ein Filetyp //ft// mit Elementen vom Typ //tm// deklariert. In der Procedure //read// soll aus einem File der nächste Wert ausgelesen werden. In der Procedure //write// soll an ein File ein Wert angehängt werden. Die Function //endfile// überprüft, ob das Ende eines Files erreicht ist. TYPE ft IS FILE OF tm ; PROCEDURE read ( f : IN ft ; value : OUT tm ; length : OUT natural ) ; PROCEDURE write ( f : OUT ft ; value : IN tm ) ; FUNCTION endfile ( f : IN ft ) RETURN boolean ; ====== Deklarationen ====== ===== Type Declaration ===== ==== Beispiele ==== Es werden zwei Integertypen //A// und //B// deklariert, die beide einen Bereich von 1 bis 10 umfassen. TYPE A IS RANGE 1 TO 10 ; TYPE B IS RANGE 1 TO 10 ; ---- Der physikalische Typ //capacitance// wird als Real-Typ mit einem Bereich von 0 bis 1E16 deklariert. Anschließend werden eine Basiseinheit und abgeleitete Einheiten deklariert. TYPE capacitance IS RANGE 0 TO 1E16 UNITS fF ; -- Femtofarad pF = 1000 fF ; -- Picofarad nF = 1000 pF ; -- Nanofarad uF = 1000 nF ; -- Microfarad END UNITS ; ---- Es wird eine rekursive Struktur aufgebaut. Zunächst wird der Typ //cell// unvollständig deklariert. Daraufhin wird der Zeigertyp //link// auf den Typ //cell// deklariert. Anschließend wird der Typ //cell// vollständig als Record deklariert. Die Elemente //succ// und //pred// werden als Zeigertypen deklariert. Dadurch kann eine verkettete Liste aufgebaut werden, bei der jedes Element einen Zeiger auf seinen Vorgänger und auf seinen Nachfolger enthält. TYPE cell ; TYPE link IS ACCESS cell ; TYPE cell IS RECORD value : integer ; succ : link ; pred : link ; END RECORD ; ---- Die sind Beispiele für standardmäßig vordefinierte Typen. //boolean// , //bit// und //character// sind Aufzählungstypen. //string// und //bit_vector// sind Felder mit jeweils beliebiger Breite (RANGE <>), wobei die maximale Breite durch den entsprechenden Typ ( //positiv// , //natural// ) vorgegeben ist. TYPE boolean IS ( false, true ) ; TYPE bit IS ( '0', '1' ) ; TYPE string IS ARRAY (positive RANGE <>) OF character ; TYPE bit_vector IS ARRAY (natural RANGE <>) OF bit ; ===== Untertypendeklaration ===== ==== Beispiele ==== Dies sind standardmäßig vordefinierte Subtypes. //natural// ist ein //integer// -Typ, beschränkt auf den Bereich von 0 bis zum maximalen //integer// -Wert. //positiv// ist ebenfalls ein //integer// -Typ, beschränkt auf den Bereich von 1 bis zum maximalen //integer// -Wert. SUBTYPE natural IS integer RANGE 0 TO integer'high ; SUBTYPE positive IS integer RANGE 1 TO integer'high ; ---- Dies sind allgemeine Beispiele, wie Subtypes durch range-constraints aus Basic-Types gebildet werden. Bei den //integer// - und //real// Subtypes werden die Bereiche mit Hilfe des Schlüsselworts //RANGE// deklariert. Bei //character// -, //string// - und //enumaration// Subtypes werden die Bereiche durch explizite Angabe eines bestimmten Ausschnitts deklariert. SUBTYPE primary_color IS color RANGE yellow TO blue ; SUBTYPE same_color IS primary_color ; SUBTYPE address_integer IS integer RANGE 0 TO 127 ; SUBTYPE human_size IS real RANGE 0.50 TO 2.50 ; SUBTYPE byte IS bit_vector (7 DOWNTO 0); SUBTYPE name IS string ( 1 TO 31 ); SUBTYPE color_10 IS colors (1 TO 10); ---- Die zwei Subtypes //sbit// und //xbit// werden als Untertypen von //zbit// deklariert, wobei beiden eine [[.:Resolution function|Auflösungsfunktion]] zugewiesen wird. Die Resolution Function sorgt bei Mehrfachzuweisungen an ein Signal für eine eindeutige Wertzuweisung. SUBTYPE sbit IS wiredX zbit ; SUBTYPE xbit IS wiredX zbit RANGE 'X' TO '1' ; ===== Konstantendeklaration ===== ==== Beispiele ==== Die Konstante //cte// ist vom Typ integer und besitzt den Wert 5. Die Konstanten //Vdd// und //Vcc// sind vom Typ //bit// und besitzten den Wert '1'. Die Konstante //minimum_setup_time// ist vom physikalischen Typ //time// und besitzt den Wert 5 ns. CONSTANT cte : integer := 5 ; CONSTANT Vdd, Vcc : bit := '1' ; CONSTANT minimum_setup_time : time := 5 ns ; ---- * Die Konstante //name// beinhaltet den String " //Dupond// ". * Der Bitvektor //address// besitzt den konstanten Wert "00110110". * Die Konstante //mask// ist als Subtype von //bit_vector// mit dem Wert "0101" deklariert. * Die Konstante //bittab// ist als Subtype von //bit_vector// mit dem Wert "000111Z1Z" deklariert. * Die Konstante //tab// ist als Subtype von //table_type// deklariert, wobei den einzelnen Elementen die konstanten Werte 2, 3, 4, -2 und 0 zugwiesen werden. CONSTANT name : string := "Dupond" ; CONSTANT address : bit_vector := "00110110" ; CONSTANT mask : bit_vector( 1 TO 3 ) := "0101" ; CONSTANT bittab : bit_vector( 1 TO 9 ) := ( 1 TO 3 => '0', 7 | 9 => 'Z', OTHERS => '1' ) ; CONSTANT tab : table_type( 0 TO 4 ) := ( 2, 3, 4, -2, 0 ) ; ---- Eine unvollständige Konstantendeklaration,wie hier für //deferred// , darf nur in der Package-Daklaration stehen. Die vollständige Konstantendeklaration muß in dem Package Body enthalten sein. Bei Veränderung des Konstantenwertes muß nur der //PACKAGE BODY// neu übersetzt werden und keine der auf das Package aufbauenden Design-Einheiten. PACKAGE P IS CONSTANT deferred : integer ; END P; PACKAGE BODY P IS CONSTANT deferred : integer := 200 ; END P ; ===== Signaldeklaration ===== ==== Weitere Definitionen ==== Die mit **REGISTER** oder **BUS** deklarierten Signale sind (kontrollierte Signale) 'guarded signals'. 'Guarded signals' müssen (aufgelöste Signale) 'resolved signals' sein. Kontrollierte Signalzuweisungen haben für 'guarded signals' folgende Bedeutung: IF guard_expression THEN sig_name <= sig_waveform ; ELSE sig_name <= NULL ; END IF ; Die Zuweisung von **NULL** an das Signal //sig_name// bedeutet, daß der Treiber dieser Signalzuweisung abgeschaltet wird. Für das 'resolved signal' hat das zur Folge: * Wurden nicht alle Treiber abgeschaltet, so wird das resultierende Signal nur anhand der nicht abgeschalteten Treiber ermittelt, * wurden alle Treiber abgeschaltet, so wird im Falle der Signaldeklaration **REGISTER** der zuletzt vorhandene Signalwert beibehalten, * wurden alle Treiber abgeschaltet, so wird im Falle der Signaldeklaration **BUS** der in der 'resolution function' angegebene Defaultwert angenommen. Das Abschalten des Signaltreibers erfolgt unmittelbar, d.h. ohne Verzögerung, nachdem die //guard_expression// den Wert //false// angenommen hat, es sei denn, es wurde für das Signal im Anschluß an dessen Deklaration als kontrolliertes Signal eine explizite Verzögerungszeit durch die DISCONNECTION Anweisung vereinbart. Ein ausführliches Beispiel dazu ist unter [[.:Disconnection specification|Disconnection Spezifikation]] zu finden. ==== Beispiele ==== Die Signale //clk_1// und //clk_2// vom physikalischen Typ //time// werden deklariert. SIGNAL clk_1, clk_2 : time ; ---- * Das Signal //address// vom Typ //bit8// wird deklariert und mit dem Wert "00110110" initialisiert. * Das Signal //bittab// wird vom Typ //bit_vector// deklariert und mit dem Wert "000111Z1Z" initialisiert. * Das Signal //tab// wird vom Typ //table_type// deklariert und mit den Werten 2, 3, 4, -2 und 0 initialisiert. SIGNAL address : bit8 := "00110110" ; SIGNAL bittab : bit_vector(1 TO 9) := ( 1 TO 3 => '0', 7 | 9 => 'Z', OTHERS => '1' ) ; SIGNAL tab : table_type( 0 TO 4 ) := ( 2, 3, 4, -2, 0 ) ; ---- Das Signal //address_bus// wird als guarded signal (BUS) vom Typ //resolved_bit_vector// und dem Initialisierungswert "10011001" deklariert. SIGNAL address_bus : resolved_bit_vector BUS := "10011001"; ---- Das Signal //resolved_s// wird als guarded signal (REGISTER) vom Typ //zbit// deklariert. Zusätzlich wird dem Signal eine [[.:resolution function|Auflösungsfunktion]] //resolution_function// zugewiesen. SIGNAL resolved_s : resolution_function zbit REGISTER ; ===== Variablendeklaration ===== ==== Anmerkungen ==== Shared variables dürfen nur im Deklarationsbereichen von Entities, Architekturen, Packages, Package Bodies und Blöcken verwendet werden. In Prozessen und Unterprogrammen dürfen keine shared variables deklariert werden. Auf eine shared variable können mehrere Prozesse zugreifen. Greifen mehrere Prozesse während eines Simulationszyklusses auf eine shared variable zu, ist die Reihenfolge der Zugriffe nicht vorgeschrieben. D.h. welche Werte innerhalb des Zimulationszyklusses gelesen werden oder welcher Wert am Schluß vorliegt ist nicht deterministisch. Siehe Beispiel unten. ==== Beispiele ==== Die Variable //count// vom Typ //positive// wird deklariert. VARIABLE count : positive ; ---- Die Variablen //index// und //memory// werden als Subtypes von den Typen //integer// und //bit_matrix// deklariert. VARIABLE index : integer RANGE 0 TO 99 := 0 ; VARIABLE memory : bit_matrix ( 0 TO 7, 0 TO 1023 ) ; ---- * //address_bus// wird als Variable vom Typ //bit8// deklariert und mit "00110110" initialisiert. * //integer_address// wird als Variable vom Typ //integer// deklariert und mit (2**nb_bit-1) initialisiert. * Die Variable //bittab// wird als subtype vom Typ //bit_vector// deklariert und mit "000111Z1Z" initialisiert. * Die Variable //tab// wird als subtype vom Typ //table_type// deklariert und mit den Werten 2, 3, 4, -2 und 0 initialisiert. VARIABLE address_bus : bit8 := "00110110" ; VARIABLE integer_address : integer := 2**nb_bit - 1 ; VARIABLE bittab : bit_vector (1 TO 9) := ( 1 TO 3 => '0', 7 | 9 => 'Z', OTHERS => '1' ) ; VARIABLE tab : table_type( 0 TO 4 ) := ( 2, 3, 4, -2, 0 ) ; ---- Beispiel für den Nichtdeterminismus von //shared variables// : In der Architektur wird eine //shared variable// deklariert, die anschließend von zwei Prozessen manipuliert wird. Es ist nicht festgelegt, ob * zuerst p1 counter um eins erhöht (counter = 1) und dann p2 counter um eins erniedrigt (counter = 0) * zuerst p2 versucht counter um eins zu erniedrigen, was zu einem Fehler aufgrund der Verletzung des Untertypen führen würde. ARCHITECTURE beh OF sv_example IS SHARED VARIABLE counter : integer RANGE 0 TO 1 := 0 ; BEGIN p1: PROCESS BEGIN counter := counter + 1 ; wait ; END PROCESS p1; p2: PROCESS BEGIN counter := counter - 1; wait ; END PROCESS p2 ; END ARCHITECTURE beh; ===== Filedeklarationen ===== ==== Anmerkungen ==== Filedeklaration der Versionen VHDL'87 und VHDL'93 sind inkompatibel! Der Standard legt nicht fest, was passieren soll, wenn mehrere logisch files ein und das selbe physikalische File lesen bzw. schreiben wollen. ==== Beispiele ==== === VHDL'87 === //simulation_output// wird als (virtuelles) Ausgabe-File vom Typ //my_file_type// mit dem physikalischen Pfad und Namen /home/usr2/sim.res deklariert. FILE simulation_output : my_file_type IS OUT "/home/usr2/sim.res" ; ---- //rom_content// wird als (virtuelles) Eingabe-File vom Typ //rom_file_type// mit dem physikalischen Namen "rom2048.txt" deklariert. FILE rom_content : rom_file_type IS IN "rom2048.txt" ; ---- //input// und //output// sind vordefinierte Files vom Typ //text// mit den physikalischen Namen //std_input// und //std_output//. FILE input : text IS IN "std_input"; FILE output : text IS OUT "std_output"; ---- //sim_output// wird als (virtuelles) Ausgabe-File (mode **IN** ist default) vom Typ //my_file_type// mit dem physikalischen Pfad und Namen /home/usr3/sim.trc deklariert. FILE sim_output : my_file_type IS OUT "/home/usr3/sim.trc" ; === VHDL'93 === //nowhere// wird als (virtuelles) File vom Typ //my_file_type// deklariert, aber nicht explizit geöffnet. FILE nowhere : my_file_type ; ---- //simulation_input// wird als (virtuelles) File vom Typ //my_file_type// mit dem physikalischen Pfad und Namen /home/usr2/sim.in deklariert. Während der Elaboration wird implizit FILE_OPEN(simulation_input,"/home/usr2/sim.res") mit dem Default READ-MODE aufgerufen. FILE simulation_input : my_file_type IS "/home/usr2/sim.res" ; ---- //simulation_output// wird als (virtuelles) Ausgabe-File vom Typ //my_file_type// mit dem physikalischen Pfad und Namen /home/usr2/sim.res deklariert. FILE simulation_output : my_file_type OPEN WRITE_MODE IS "/home/usr2/sim.res" ; ===== Schnittstellendeklaration ===== * Interface-Declarations definieren Schnittstellenobjekte von einem genau festgelegten Typ. * Schnittstellenobjekte sind (Schnittstellen-) Konstanten, (Schnittstellen-) Signale, (Schnittstellen-) Variablen und (Schnittstellen-) Dateien. ==== interface_signal_declaration ==== ''[ [[.:signal_declarations|signal]] ] [[.:bnf#identifier_list]] : [ [[.:bnf#mode]] ] [[.:subtype_declarations|subtype_indication]] [ [[.:signal_declarations|bus]] ] [ := static _[[.:bnf#expression]] ]'' -- subtype_indication darf kein Datei- oder Pointertyp sein. ==== interface_file_declaration ==== ''file [[.:bnf#identifier_list]] : [[.:bnf#subtype_indication]]'' -- subtype_indication muß einen Untertyp eines Deteityps bezeichnen. ==== mode ==== * in -- Ports können nicht geschrieben werden; Standardmode * out -- Ports können nicht gelesen werden * inout -- Ports können gelesen und geschrieben werden * buffer -- Ports können gelesen und nur von einer Quelle geschrieben werden * linkage -- Ports können gelesen und geschrieben werden, aber nur als "actuals". ===== Alias-Deklaration ===== ==== Ergänzungen ==== Alle benamten Dinge bis auf Labels, Schleifenparameter und Generate-Parameter kann mit einem Alias versehen werden. Ein Alias für ein Objekt (Konstanten, Variablen, Signale, File) nennt man object alias. Alle anderen nennt man nonobject alias. Das Alias eines überladbaren Objekts ist selbst wieder überladbar. Für object aliases gelten folgende Regeln: * Signaturen sind nicht erlaubt. * Der Name in einer Aliasdeklaration muß ein statischer Name (See [[.:Name]]) sein. Wird der Untertyp in der Aliasdeklaration angegeben, muß dieser mit dem Typ des angegeben Namen übereinstimmen. Mehrdimensionale Arrays als Untertyp sind verboten. Folgende Regeln gelten: * Wenn die Untertypenangabe fehlt oder vorhanden ist und einen unbeschränkten Feldtyp bezeichnet: * Wenn das Alias einen Feldausschnitt bezeichnet, dann wird der Untertyp des Objekts als solchiger Typ des Feldausschnitt betrachtet. * Ansonsten besitzt das (neue) Objekt den Typ welcher durch das (alte) Objekt vorgegeben ist. * Wenn eine vorhandene Untertypenangabe einen beschränkten Feldtyp bezeichnet, dann besitzt das Objekt diesen angegeben Untertyp. Der angegebene Untertyp muß passende Einzelelemente bezüglich des Typen des (alten) Objekts haben. * Wenn eine vorhandene Untertypenangabe einen skalaren Typ bezeichnet, dann besitzt das Objekt diesen angegeben Untertyp. Desweitern müssen altes und neues Objekt die selben Wertegrenzen und Richtungsdefinition besitzen. * Das gleiche gilt für Referenzen von Attributen, bei denen der Prefix des Attributname ein Alias bezeichnet. * Eine Referenz eines object alias ist automatisch eine Referenz auf das eigentliche Objekt (gilt auch für Feldausschnitte). Für nonobject aliases gelten folgende Regeln: * Untertypenangaben sind nicht erlaubt. * Bezeichnet der Name ein Unterprogramm (auch Operatoren) oder einen Wert eines Aufzählungstyp, so ist eine Signatur erforderlich. Die Signatur muß dabei mit der Parameter und Rückgabetypen Kombination (See [[.:Overloading|Überladen]]) genau eines der Unterprogramme oder des Aufzählungswertes übereinstimmen. * Bezeichnet der Name einen Aufzählungstypen, so werden durch die Aliasdeklarationen für jedes Element des ursprünglichen Aufzählungstyps eine Aliasdeklaration impliziert (alias_designator = Aufzählungselementnamen; name = urzprünglicher Aufzählungstyp.Aufzählungselementnamen). * Gleiches gilt bei einem Alias für einen physikalischen Typ. * Bezeichnet der Name einen Typ, dann impliziert die Aliasdeklaration weitere Aliasdeklarationionen für damit verbundene Operatoren und gegebenenfalls für entsprechende Werte und Einheiten. Jede implizite Operator-Aliasdeklaration hat eine Signatur, die genau eines der Parameter und Rückgabetypen Kombination (2.3) des Operators entspricht. ==== Beispiele ==== Die Konstante //tc// ist durch die Alias-Deklaration nun auch über den Namen //delay// ansprechbar. CONSTANT tc : time := 2.5 ns ; ALIAS delay : time IS tc ; ---- Durch das Alias kann die Variable //vector// nun über den Namen //reverse_vector// angesprochen werden, wobei hier die Indizes von 8 bis 1 gehen. VARIABLE vector : bit_vector(0 TO 7); ALIAS reverse_vector : bit_vector ( vector'length DOWNTO 1 ) IS vector ; ---- Hier wird die Variable //real_number// unterschiedlich aliased. Mit //sign// ist das MSB von //real_number// ansprechbar. Mit //mantissa// werden die Elemente 8 bis 31 von //real_number// angesprochen, wobei die Indizes hier von 0 bis 23 gehen. Mit //exponent// werden die Elemente 1 bis 7 von //real_number// angesprochen, wobei die Indizes hier ebenfalls von 1 bis 7 gehen. VARIABLE real_number : bit_vector ( 0 TO 31 ) ; ALIAS sign : bit IS real_number(0) ; ALIAS mantissa : bit_vector( 0 TO 23 ) IS real_number( 8 TO 31 ) ; ALIAS exponent : bit_vector( 1 TO 7 ) IS real_number( 1 TO 7 ) ; ---- Der vordefinierte Typ //BIT// aus dem automatisch verfügbaren Package //STANDARD// und der Bibliothek //STD// wird mit dem Alias //std_bit// versehen. Damit werden automatisch weitere Alias-deklarationen für die Werte des Aufzählungstyps und die vordefinierten Operatoren impliziert. ALIAS std_bit IS STD.STANDARD.BIT ; -- ALIAS `0' IS STD.STANDARD .'0' -- [ RETURN STD.STANDARD.BIT ] ; -- ALIAS `1' IS STD.STANDARD .'1' ; -- [ RETURN STD.STANDARD.BIT ] ; -- ALIAS "and" IS STD.STANDARD ."and" ; --[ STD.STANDARD.BIT , STD.STANDARD.BIT -- RETURN STD.STANDARD.BIT ] ; -- ALIAS "or" IS STD.STANDARD ."or" ; --[ STD.STANDARD.BIT , STD.STANDARD.BIT -- RETURN STD.STANDARD.BIT ] ; -- ··· ===== Attributdeklaration ===== Mit Attributen können Eigenschaften von Objekten (z.B. Signalen) abgefragt werden. Damit kann in vielen Fällen eine elegantere und kürzere VHDL-Beschreibung gestaltet werden. Die wichtigsten sind bereits [[.:Predefined attributes|vordefinierte Attribute]]. Für eigene Attribute muß eine entsprechende Funktion geschrieben werden, die dann zu jeder Zeit den Wert des Attributes liefert. Weiteres unter [[.:Attribute specification|Attribut Spezifikation]]. ==== Beispiele ==== //capacitance_value// wird als Attribut vom Typ //capacitance// deklariert. ATTRIBUTE capacitance_value : capacitance ; ---- Das hier deklarierte Attribute //pin_number// ist vom Subtype //pin_natural// . SUBTYPE pin_natural IS natural RANGE 1 TO 24 ; ATTRIBUTE pin_number : pin_natural ; ---- Es werden zwei verschiedene Attribute deklariert. //location// ist vom Typ //coordinate// , einem Record. //pin_no// ist vom Typ //positive// , einem Subtype von //integer// . TYPE coordinate IS RECORD x, y : integer ; END RECORD ; TYPE positive IS integer RANGE 1 TO integer'high ; ATTRIBUTE location : coordinate ; ATTRIBUTE pin_no : positive ; ---- Mit [[.:Predefined attributes|vordefinierten Attributen]] kann die Schleifenanweisung auch anders formuliert werden : FOR i IN a1'LOW TO a1'HIGH FOR i IN a1'RIGHT TO a1'LEFT FOR i IN a1'REVERSE_RANGE FOR i IN a1'RANGE SIGNAL a1: bit_vector(3 DOWNTO 0) ; ... PROCESS (a) BEGIN z<= "0000"; FOR i in 0 TO 3 LOOP IF (a = i) THEN z(i) <= '1' ; END IF ; END LOOP ; END PROCESS ; ... ===== Komponentendeklaration ===== ==== Beispiele ==== Es wird die Component //gen_clock// deklariert, die nur den Ausgang //clk// als Schnittstelle nach außen besitzt. COMPONENT gen_clock PORT ( clk : OUT tri_bit ) ; END COMPONENT ; ---- Die hier deklarierte Component //adder_8_bit// besitzt die Eingänge //a// , //b// und //cin// sowie die Ausgänge //sum// und //cout// . COMPONENT adder_8_bit PORT (a, b : IN bit_vector(1 TO 8); cin : IN bit ; sum : OUT bit_vector(1 TO 8); cout: OUT bit ) ; END COMPONENT ; ---- Die hier deklarierte Component //adder_n_bit// ist über den Generic //n// parametrisiert. Die Breite der Eingangsvektoren //a// und //b// sowie des Ausgangsvektors //sum// ergibt sich aus dem Wert des Generics //n// . COMPONENT adder_n_bit GENERIC ( n : positive ) ; PORT (a, b : IN bit_vector(1 TO n); cin : IN bit ; sum : OUT bit_vector(1 TO n); cout: OUT bit ) ; END COMPONENT ; ===== Gruppentemplatedeklaration ===== ==== Beispiele ==== Gruppen dieses Typs bestehen aus zwei Signalen GROUP pin2pin IS ( SIGNAL , SIGNAL ) ; ---- Gruppen dieses Typs bestehen aus einer beliebigen Anzahl von Signalen GROUP pin_set IS ( SIGNAL <>) ; ---- Gruppen dieses Typs bestehen aus einer beliebigen Anzahl von Dateien. GROUP file_groups IS ( FILE <>) ; ---- Gruppen dieses Typs bestehen aus einer beliebigen Anzahl von Gruppen. GROUP gog IS ( GROUP <>) ; ===== Gruppendeklaration ===== ==== Beispiele ==== Gruppen vom Typ //pin2pin// werden deklariert. GROUP pinpair1 : pin2pin (clk, q1) ; GROUP pinpair2 : pin2pin (clk, q2) ; ---- Gruppe der beiden vorher definierten Gruppen. GROUP clocked : gog (pinpair1, pinpair2); ---- * Der Gruppentyp //path// wird deklariert. * Die Gruppe //a_to_s// wird deklariert. * Das Attribut //propagation_delay// wird deklariert. * Das Attribut //propagation_delay// wird der Gruppe //a_to_s// verbunden und mit dem Wert 250 ns belegt. GROUP path IS ( SIGNAL , SIGNAL ) ; GROUP a_to_s : path (a,s) ; ATTRIBUTE propagation_delay : time ; ATTRIBUTE propagation_delay OF a_to_s : GROUP IS 250 ns ; ---- * Der Signalgruppemtyp //pin_set// wird deklariert. * Der Gruppengruppentyp //paths// wird deklariert. * Die Signalsgruppen //sources// und //targets// werden deklariert. * Die Gruppengruppe //ins_to_outs// wird deklariert. * Das Attribut //propagation_delay// wird deklariert. * Das Attribut //propagation_delay// wird der Gruppe //ins_to_outs// verbunden und mit dem Wert //delay// belegt. GROUP pin_set IS ( SIGNAL <>) ; GROUP paths IS ( GROUPS <>) ; GROUP sources : pin_set (inp1, inp2) ; GROUP targets : pin_set (outp1, outp2) ; GROUP ins_to_outs : paths (sources, targets) ; ATTRIBUTE propagation_delay : time ; ATTRIBUTE propagation_delay OF ins_to_outs : GROUP IS delay ; ====== Spezifikation ====== ===== Attribut Spezifikation ===== ==== Beispiele ==== Values for the attribute //pin_number// are determined. For the signal //cin// the attribute value is //10// and for the signal //cout// it is //5// . ATTRIBUTE pin_number OF cin : SIGNAL IS 10 ; ATTRIBUTE pin_number OF cout : SIGNAL IS 5 ; ---- Der Wert des Attributes //instance_location// beträgt für das Label //adder_1 (10,15)// und für alle anderen Labels //(25,65)// . ATTRIBUTE instance_location OF adder_1 : LABEL IS ( 10, 15 ) ; ATTRIBUTE instance_location OF OTHERS : LABEL IS ( 25, 65 ) ; ---- * Das Attribut //author// der Entity //add_entity// wird mit dem String //Martin// belegt. * Das Attribut //is_generic// der Component //cmos_nand// wird mit dem Wert //false// belegt. * Das Attribut //creation_date// der Architecture //add_arc// wird mit dem Record //(14,Aug,95)// belegt. * Das Attribut //safety// der Procedure //arithm_conv// wird mit dem Wert //bug// belegt. * Das Attribut //confidentiality// des Package //cmos_pkg// wird mit dem Wert //restrictive// belegt. ATTRIBUTE author OF add_entity : ENTITY IS "Martin" ; ATTRIBUTE is_generic OF cmos_nand : COMPONENT IS false ; ATTRIBUTE creation_date OF add_arc : ARCHITECTURE IS (11, aug, 95) ; ATTRIBUTE safety OF arithm_conv : PROCEDURE IS bug ; ATTRIBUTE confidentiality OF cmos_pkg : PACKAGE IS restrictive ; ---- Mit [[.:predefined attributes|vordefinierten Attributen]] kann die Schleifenanweisung auch anders formuliert werden : FOR i IN a1'LOW TO a1'HIGH FOR i IN a1'RIGHT TO a1'LEFT FOR i IN a1'REVERSE_RANGE FOR i IN a1'RANGE SIGNAL a1: bit_vector(3 DOWNTO 0) ; ... PROCESS (a) BEGIN z<= "0000" : FOR i in 0 TO 3 LOOP IF (a = i) THEN z(i) <= '1' ; END IF ; END LOOP ; END PROCESS ; ... ===== Konfiguration Spezifikation ===== ==== Anmerkungen ==== In der generic map aspect muß ein actual ein Ausdruck oder das reservierte Wort **OPEN** sein. In der port map aspect muß ein actual ein signal, ein Ausdruck oder das reservierte Wort **OPEN** sein. (In VHDL'87 durften Eingänge nur mit Signalen belegt werden; in VHDL'93 dürfen globale statische Werte auf Eingänge gelegt werden.) ==== Beispiele ==== Für die Components //add_comp// der Labels //c1// , //c2// und //c3// soll die Verhaltensbeschreibung //add_1// aus der Default-Bibliothek ( //work// ) verwendet werden. In den restlichen Labels ( **OTHERS** ) soll für die Components //add_comp// die Beschreibung //add_configuration// aus der Default-Bibliothek ( //work// ) verwendet werden. FOR c1, c2, c3 : add_comp USE ENTITY work.add_1( behaviour ) ; FOR OTHERS : add_comp USE CONFIGURATION work.add_configuration; ---- Alle verwendeten Components //register_comp// sollen nicht verbunden werden. FOR ALL : register_comp USE OPEN ; ---- Für die Components //nand2_comp// der Labels //c(1)// bis //c(5)// soll die Entity nand mit dem Generic //N=2// und der entsprechenden Ein-/Ausgangsverknüpfung ( **PORT MAP** ) verwendet werden. Für die Component //nand2_comp// des Labels //c(6)// soll die Configuration //nand2_configuration// aus der Bibliothek //my_lib// mit der entsprechenden Ein-/Ausgangsverknüpfung ( **PORT MAP** ) verwendet werden. FOR c( 1 TO 5 ) : nand2_comp USE ENTITY nand( arc ) GENERIC MAP ( N => 2 ) PORT MAP ( I(1) => a, I(2) => b, O => s ) ; FOR c(6) : nand2_comp USE CONFIGURATION my_lib.nand2_configuration PORT MAP ( a, b, s ) ; ===== Disconnection Spezifikation ===== ==== Beispiele ==== //a// wird als Guarded Signal vom Typ [[.:signal declarations|REGISTER]] deklariert. Wird während der Simulation ein Treiber für das Signal //a// deaktiviert, so geschieht das um 1 ns zeitverzögert. SIGNAL a : resolved_type REGISTER ; DISCONNECT a : resolved_type AFTER 1 ns; ---- //sig1// , //sig2// und //sig3// werden als Guarded Signals vom Typ [[.:signal declarations|REGISTER]] deklariert. Die Treiber für //sig1// werden während der Simulation um 5 ns und die der anderen Signale um 8 ns verzögert abgeschaltet. SIGNAL sig1, sig2, sig3 : resolved_bit REGISTER ; DISCONNECT sig1 : resolved_bit AFTER 5 ns ; DISCONNECT OTHERS : resolved_bit AFTER 8 ns ; ---- //bus_a// und //bus_b// werden als Guarded Signals vom Typ [[.:signal declarations|bus]] deklariert. Die Treiber für beide Signale werden während der Simulation um 6 ns ( //delay// + 1 ns) verzögert abgeschaltet. CONSTANT delay : time := 5 ns ; SIGNAL bus_a, bus_b : resolved_zbit_vector32 BUS ; DISCONNECT ALL : resolved_zbit_vector32 AFTER delay + 1 ns ; ---- Im **PACKAGE** //fourval// wird eine vierwertige Logik //mvl4// und ein entsprechender Vektor definiert. Es wird die Funktion //resolved// deklariert. Daraufhin kann ein 'resolved signal' als **SUBTYPE** abgeleitet werden. Im **PACKAGE BODY** wird die Funktion //resolved// beschrieben. * Wechselt das Eingangssignal //choice// auf //1// , so wird der Signaltreiber des ersten Blocks aktiv und gibt das erste Eingangssignal nach 20 ns an den Ausgang weiter. * Wechselt //choice// auf //2// , so wird durch den zweiten Block das zweite Eingangssignal nach 18 ns ebenfalls auf den Ausgang gelegt. Da der erste Signaltreiber aber erst nach 25 ns abschaltet, sind für 7 ns zwei Treiber aktiv. * Das resultierende Signal wird durch die 'resolution function' des Ausgangssignals ermittlelt. * Wechselt //choice// auf einen Wert ungleich //1// oder //2// , so schaltet der zuletzt aktive Treiber nach 25 ns ab und das Ausgangssignal wechselt in den Defaultwert (in diesem Fall 'Z'), da es als [[.:signal declarations|bus]] deklariert ist. * Bei einer Deklaration als [[.:signal declarations|REGISTER]] würde der letzte Signalwert erhalten bleiben. PACKAGE fourval IS TYPE mvl4 IS ('X','0','1','Z') ; TYPE mvl4_vector IS ARRAY (natural RANGE <>) OF mvl4 ; FUNCTION resolved (a: mvl4_vector) RETURN mvl4 ; SUBTYPE mvl4_r IS resolved mvl4 ; END fourval ; PACKAGE BODY fourval IS FUNCTION resolved (a: mvl4_vector) RETURN mvl4 IS VARIABLE result : mvl4 := 'Z' ; -- Defaultwert: 'Z' BEGIN ... RETURN result ; END resolved ; END fourval ; USE work.fourval.ALL ; ENTITY mux_2_1 IS PORT (in_signals : IN mvl4_vector (1 TO 2) ; choice : IN integer ; out_signal : OUT mvl4_r BUS ) ; END mux_2_1 ; ARCHITECTURE with_guards OF mux_2_1 IS DISCONNECT out_signal : mvl4_r AFTER 25 ns ; BEGIN choice_1 : BLOCK (choice = 1) BEGIN out_signal <= GUARDED in_signals(1) AFTER 20 ns ; END BLOCK ; choice_2 : BLOCK (choice = 2) BEGIN out_signal <= GUARDED in_signals(2) AFTER 18 ns ; END BLOCK ; END with_guards ; ====== Namen ====== ===== Name ===== ===== Einfache Namen ===== ==== Definition ==== * [[.:bnf#identifier]] Über einen einfachen Namen können verschiedene Objekte im VHDl-Code angesprochen und manipuliert werden. ===== Auswählende Namen ===== ==== Beispiele ==== Es wird das Element //opcode// des Records //instruction// angesprochen. instruction.opcode ---- Es werden alle Elemente ( **ALL** ) angesprochen, auf die der Zeiger //ptr// zeigt. ptr. ALL ---- Es wird die Design-Einheit //SN74LS221// aus der Bibliothek //ttl// angesprochen. ttl.SN74LS221 ---- Angesprochen werden alle Design-Einheiten aus der Bibliothek //cmos// . cmos. ALL ---- Es wird die Entity //voltage// aus dem Package //measurements// angesprochen. measurements.voltage ---- Angesprochen werden alle Entities aus dem Package //standard// . standard. ALL ---- Es wird die Entity //data// angesprochen, die in dem Prozeß //p// definiert ist. p.data ===== Indizierte Namen ===== ==== Beispiele ==== Es wird das 5'te Element des Arrays //register_array// angesprochen. register_array(5) ---- Es wird das Element mit den Inidzes //(1024,7)// des zweidimensionalen Arrays //memory_cell// angesprochen. memory_cell( 1024, 7 ) ===== Bereichsnamen ===== ==== Beispiel ==== Es werden verschieden Slices angesprochen. * Der erste Slice spricht den Bereich //0// bis //7// von //r15// an. * Der zweite Slice spricht den Bereich //24// bis //1// von //data// an. * Der dritte Slice ist ungültig, weil die Indizierungsrichtung in Deklaration und Slice entgegengesetzt ist. SIGNAL r15 : bit_vector( 0 TO 31 ) ; CONSTANT data : bit_vector(31 DOWNTO 0); r15( 0 TO 7 ) ; data( 24 DOWNTO 1 ) ; data( 24 TO 25 ) ; ===== Attributnamen ===== ==== Beispiele ==== Angesprochen wird das linke Element der ersten Dimension des ein- oder mehrdimensionalen Arrays //register// . register'left(1) ---- Das Attribut //fanout// liefert die Anzahl der von //output// getriebenen Signale. output'fanout ---- Es wird das um 5 ns verzögerte Signal //clk// angesprochen. clk'delayed( 5 ns ) ---- Mit [[.:predefined attributes|vordefinierten Attributen]] kann die Schleifenanweisung auch anders formuliert werden : FOR i IN a1'LOW TO a1'HIGH FOR i IN a1'RIGHT TO a1'LEFT FOR i IN a1'REVERSE_RANGE FOR i IN a1'RANGE SIGNAL a1: bit_vector(3 DOWNTO 0) ; ... PROCESS (a) BEGIN z<= "0000" : FOR i in 0 TO 3 LOOP IF (a = i) THEN z(i) <= '1' ; END IF ; END LOOP ; END PROCESS ; ... ====== Ausdrücke ====== ===== Ausdruck ===== ==== Definitionen ==== === expression === Jeder Ausdruck entspricht einer Gleichung, die eine Vorschrift zur Berechnung eines Wertes bildet. ===== Logische Operatoren ===== ==== Definition ==== Die logischen Operatoren **AND** , **OR** , NAND , **NOR** , **XOR**, **XNOR** und **NOT** sind für die vordefinierten Datentypen //bit// und //boolean// definiert. Sie können auch auf eindimensionale Feld-Typen ( //Array// ), deren Elemente vom Typ //bit// oder //boolean// sind, angewendet werden. Bei Anwendung der Operatoren **AND** , **OR** , **NAND** , **NOR** , **XOR** und **XNOR** ist im letzteren Fall folgendes zu beachten : * Die beiden Felder müssen die gleiche Feldlänge haben. * Die Operation wird mit den betreffenden Elementen beider Felder ausgeführt. * Das Ergebnis ist ein Feld, das die gleiche Feldtiefe besitzt wie der linke Operand. Entsprechendes gilt für den Operator **NOT** , wobei allerdings die Operation mit jedem einzelnen Element des Feldes durchgeführt wird. Alle binären logischen Operatoren besitzen die niedrigste Priorität. Der unäre Operator **NOT** hat höchste Priorität. ==== Wahrheitstafel ==== Das Symbol T steht für true (Typ //boolean// ), '1' (Typ bit ). Das Symbol F steht für false (Typ //boolean// ), '0' (Typ bit ). ===== Relationale Operatoren ===== ==== Definition ==== * Vergleichsoperatoren dienen zum Vergleichen der Operanden bezüglich der Gleichheit, Ungleichheit und Größenverhältnisse. * Die Operanden müssen stets vom gleichen Typ sein. * Das Ergebnis der Operation ist vom vordefinierten Typ //boolean// . ==== Anmerkungen ==== Bei einem Vergleich von diskreten Feldern werden die "linken" Werte verglichen! Vektoren z.B. werden also nach links ausgerichtet und verglichen. ("110" < "1000" ergibt also false, da nur die ersten drei Stellen ausschlaggebend sind) ==== Übersicht ==== ^ Operator ^ Operation ^ Typ der Operanden ^ Typ des Ergebnisses ^ | = | Gleichheit | beliebig | boolean | | /= | Ungleichheit | beliebig | boolean | | < <= \\ > >= | Vergleich | jeder skalare Typ oder ein Feldtyp | boolean | ===== Shift Operatoren ===== ==== Definition ==== Die Shift Operatoren sind vordefiniert für beliebige eindimensionale Felder mit den Elemententypen **BIT** oder **BOOLEAN** . Die Operatoren sind folgendermaßen definiert, wobei L der linke Operand und R der rechte Operand ist: * **L sll R** : Shifte L um R Positionen nach links (R≥0) bzw. rechts (R<0). Die vordersten (R≥0) bzw. hintersten (R<0) Werte "fallen weg" und der Wert T'LEFT wird nachgeschoben. T ist dabei der Typ der Elemente des Feldes. * **L srl R** : Shifte L um R Positionen nach rechts (R≥0) bzw. links (R<0). Die hintersten (R≥0) bzw. vordersten (R<0) Werte "fallen weg" und der Wert T'LEFT wird nachgeschoben. T ist dabei der Typ der Elemente des Feldes. * **L sla R** : Shifte L um R Positionen nach links (R≥0) bzw. rechts (R<0). Die vordersten (R≥0) bzw. hintersten (R<0) Werte "fallen weg" und der Wert L'RIGHT (R≥0) bzw. L'LEFT (R<0) wird nachgeschoben. Der letzte (R≥0) bzw. erste (R<0) Wert von L wird also nachgeschoben. * **L sra R** : Shifte L um R Positionen nach rechts (R≥0) bzw. links (R<0). Die hintersten (R≥0) bzw. vordersten (R<0) Werte "fallen weg" und der Wert L'LEFT (R≥0) bzw. L'RIGHT (R<0) wird nachgeschoben. Der erste (R≥0) bzw. letzte (R<0) Wert von L wird also nachgeschoben. * **L rol R** : Rotiere L um R Positionen nach links (R≥0) bzw. rechts (R<0). Die vordersten (R≥0) bzw. hintersten (R<0) Werte werden hinten (R≥0) bzw. vorne (R<0) nachgeschoben. * **L ror R** : Rotiere L um R Positionen nach rechts (R≥0) bzw. links (R<0). Die hintersten (R≥0) bzw. vordersten (R<0) Werte werden vorne (R≥0) bzw. hinten (R<0) nachgeschoben. ==== Übersicht ==== ^ Operator ^ Operation ^ Typ des linken Operanden ^ Typ des rechten Operanden ^ Typ des Ergebnisses ^ | sll | Shift Left Logical | Beliebiges eindimensionales Feld mit Elementen des Typs BIT oder BOOLEAN | INTEGER | Typ des linken Operanden | | srl | Shift Right Logical | Beliebiges eindimensionales Feld mit Elementen des Typs BIT oder BOOLEAN | INTEGER | Typ des linken Operanden | | sla | Shift Left Arithmetic | Beliebiges eindimensionales Feld mit Elementen des Typs BIT oder BOOLEAN | INTEGER | Typ des linken Operanden | | sra | Shift Right Arithmetic | Beliebiges eindimensionales Feld mit Elementen des Typs BIT oder BOOLEAN | INTEGER | Typ des linken Operanden | | rol | Rotate Left Logical | Beliebiges eindimensionales Feld mit Elementen des Typs BIT oder BOOLEAN | INTEGER | Typ des linken Operanden | | ror | Rotate Right Logical | Beliebiges eindimensionales Feld mit Elementen des Typs BIT oder BOOLEAN | INTEGER | Typ des linken Operanden | ===== Addierende Operatoren ===== ==== Definition ==== Die Additionsoperatoren + und - sind in ihrer bekannten Bedeutung für jeden numerischen Typ vordefiniert. Der Verkettungsoperator (Concatination) & ist für beliebige eindimensionale Feldtypen vordefiniert. ==== Übersicht ==== ^ Operator ^ Operation ^ Typ des linken Operanden ^ Typ des rechten Operanden ^ Typ des Ergebnisses ^ | + | Addition | beliebiger numerischer Typ | gleicher Typ | gleicher Typ | | - | Subtraktion | beliebiger numerischer Typ | gleicher Typ | gleicher Typ | | & | Verkettung (Concatination) | beliebiger Feldtyp | gleicher Feldtyp | gleicher Feldtyp | | ::: | ::: | beliebiger Feldtyp | Elementtyp | gleicher Feldtyp | | ::: | ::: | Elementtyp | beliebiger Feldtyp | gleicher Feldtyp | | ::: | ::: | Elementtyp | Elementtyp | beliebiger Feldtyp | ==== Ergänzung ==== Die Vorzeichen + und - sind für jeden numerischen Typ vordefiniert. Nach den Prioritätsregeln für Ausdrücke darf ein Vorzeichenoperand nicht Multiplikationsoperatoren, dem Exponentialoperator ** oder den Operatoren **ABS** und **NOT** folgen. Z. B. sind folgende Ausdrücke syntaktisch falsch : * A / +B * A ** -B Erlaubt sind jedoch Ausdrücke der folgenden Form : * A / (+B) * A ** (-B) ===== Multiplizierende Operatoren ===== ==== Definition ==== Die Multiplikationsoperatoren * und / sind in ihrer bekannten Bedeutung für jeden Integer- und Fließkommatyp vordefiniert. Die Operatoren **MOD** und **REM** sind für beliebige Integer-Typen vordefiniert. Das Ergebnis jeder Operation ist vom gleichen Typ wie die (typgleichen) Operanden. ==== Übersicht 1 ==== ^ Operator ^ Operation ^ Typ des linken Operanden ^ Typ des rechten Operanden ^ Typ des Ergebnisse ^ | * | Multiplikation | beliebiger Integer-Typ | gleicher Typ | gleicher Typ | | ::: | ::: | beliebiger Fließkomma-Typ | gleicher Typ | gleicher Typ | | / | Division | beliebiger Integer-Typ | gleicher Typ | gleicher Typ | | ::: | ::: | beliebiger Fließkomma-Typ | gleicher Typ | gleicher Typ | | MOD | Modulo | beliebiger Integer-Typ | gleicher Typ | gleicher Typ | | REM | Rest | beliebiger Integer-Typ | gleicher Typ | gleicher Typ | ==== Ergänzungen ==== Die Operatoren * und / sind für jeden beliebigen physikalischen Typ vordefiniert. ==== Übersicht 2 ==== ^ Operator ^ Operation ^ Typ des linken Operanden ^ Typ des rechten Operanden ^ Typ des Ergebnisse ^ | * | Multiplikation | beliebiger physikalischer Typ | integer | gleicher Typ wie linker Operand | | ::: | ::: | beliebiger physikalischer Typ | real | gleicher Typ wie linker Operand | | ::: | ::: | integer | beliebiger physikalischer Typ | gleicher Typ wie rechter Operand | | ::: | ::: | real | beliebiger physikalischer Typ | gleicher Typ wie rechter Operand | | / | Division | beliebiger physikalischer Typ | integer | gleicher Typ wie linker Operand | | ::: | ::: | beliebiger physikalischer Typ | real | gleicher Typ wie linker Operand | | ::: | ::: | beliebiger physikalischer Typ | gleicher Typ | universal integer | ===== Verschiedene Operatoren ===== ==== Definition ==== Der unäre Operator **ABS** ist für jeden numerischen Typ vordefiniert. Der Potenzoperator ** ist für jeden Integer-und Fließkommatyp vordefiniert. Der rechte Operand, der Exponent, ist stets vom vordefinierten Typ //integer// . ==== Der Operator ABS ==== ^ Operator ^ Operation ^ Typ des Operanden ^ Typ des Ergebnisses ^ | ABS | absoluter Wert | beliebiger numerischer Typ | gleicher Typ | ==== Der Operator ** ==== ^ Operator ^ Operation ^ Typ des linken Operators ^ Typ des rechten Operators ^ Typ des Ergebnisses ^ | ** | Potenz | beliebiger Integer-Typ | //integer// | gleicher Typ wie linker Operand | | ::: | ::: | beliebiger Fließkomma-Typ | //integer// | gleicher Typ wie linker Operand | === Anmerkung === Das Potenzieren mit negativen Exponenten ist nur möglich, wenn der linke Operand ein Fließkomma-Typ ist. ===== Buchstabensymbole (Literal) ===== ==== Beispiele ==== Ein Literal vom Typ //universal_real// (abstrakter Typ). 3.14159_26536 ---- Ein Literal vom Typ //universal_integer// (abstrakter Typ). 5280 ---- Ein Literal von einem physikalischen Typ. 10.7 ns ---- Ein Literal vom Typ //bit_string// . O"4777" ---- Ein Literal vom Typ //string// . "54LS281" ---- Ein //String// -Literal, das ein leeres Feld darstellt. "" ===== Aggregate ===== ==== Beispiele ==== Dieses Aggregat besitzt die Breite 4. (a_bit, b_bit, c_bit, d_bit) ---- Mit diesem Aggregat kann man den einzelnen Elementen eines Feldes unterschiedliche Werte zuweisen. (7=>'1', 5 downto 1 => '1', 6 => b_bit, others => '0') ---- Mit diesem Aggregat kann man allen einzelnen Elementen eines zweidimensionalen Feldes den Wert //0// zuweisen. (others => (others => '0')); ===== Funktionsaufruf ===== ==== Beispiele ==== Durch diesen Funktionsaufruf erhält //exnor_out// den Rückgabewert der Funktion //exnor// . exnor_out <= exnor(in1, in2); ---- //x2// erhält den Rückgabewert der Funktion //exnor// . Die Übergabeparameter //a// und //b// besitzen dabei die Werte der angegebenen Vektorbereiche. x2 <= exnor ( a => in1(2 downto 0), b => in2(2 downto 0) ); ---- i erhält die Summe der Rückgabewerte der beiden Funktionen //bit_to_integer// und //count_ones// . i <= bit_to_integer(bit_a => in(8)) + count_ones(in2); ===== Qualified Expression ===== ==== Beispiel ==== Durch die qualifizierten Ausdrücke wird der Typ des jeweiligen Return-Wertes explizit ausgewählt und damit auch die passende '='-Funktion. w <= (a=b) = (c=d); x <= (a=b) = mvl4'(c=d); y <= (a=b) = bit'(c=d); z <= (a=b) = boolean'(c=d); ---- Durch den qualifizierten Ausdruck wird aus zwei Einzelbittypen ein Vektor mit dem (Unter-) Typ vec_type gebildet, dessen Wert in der case-Anweisung überprüft wird CASE vec_type'(A & B) is when "00" => VALUE <= 0; when "01" => VALUE <= 1; when "10" => VALUE <= 2; when "11" => VALUE <= 3; when others => VALUE <= 9; end case; ===== Typenkonvertierung ===== ==== Beispiele ==== Die //float_varibale// wird durch Abrunden bzw. Aufrunden in den Typ //integer// umgewandelt integer(float_varibale) ---- Die //integer_variable// wird in den Typ //real// umgewandelt. real(integer_variable) ===== Allocator ===== ==== Beispiele ==== Es wird Speicher für den Typ //node// allokiert. Bei der ersten Variante wird der Default-Wert des Typs //node// zur Initialisierung verwendet, bei den anderen die in den Klammern angegebenen Werte. NEW node NEW node'( 15 ns, NULL ) NEW node'( delay => 5 ns, next => stack ) ---- Durch die Initialisierung mit "//01100010//" wird die Breite des allokierten Objektes auf 8 festgelegt. NEW bit_vector'( "01100010" ) ---- Hier wird die Größe des allokierten Speicherbereichs durch die Festlegung der Stringbreite (10) begrenzt. NEW string( 1 TO 10 ) ===== Statischer Ausdruck ===== ==== Definition ==== Es gibt zwei Kategorien von statischen Ausdrücken. Ein Ausdruck ist genau dann //lokal statisch// , wenn jeder Operator in diesem Ausdruck ein implizit definierter Operator ist, die Operanden sowie die Ergebnisse skalar sind und jedes Primary in diesem Ausdruck ein //local static Primary// ist; als //local static Primaries// gelten: * Werte jeglichen Typs außer dem Typ **TIME** . * Konstanten, die explizit durch eine Konstantendeklaration deklariert und mit einem lokal statischen Ausdruck initialisiert sind. (NICHT verschobene [[.:constant declarations|(deferred) Konstanten]]). * Ein Alias dessen Name-Part ein lokal statisches Primitiv ist. * Funktionsaufrufe, deren Namen einen vordefinierten Operator darstellen und deren aktuelle Parameter jeweils lokal statische Ausdrücke sind. * Vordefinierte Attribute welche einen Wert liefern (außer `**PATH_NAME** ) und dessen Prefix entweder einen lokal statischen Untertyp besitzen oder ein Objektname eines lokal statischen Untertyp sind. * Vordefinierte Attribute, außer ` **LAST_EVENT** , ` **LAST_ACTIVE** , ` **LAST_VALUE** , ` **DRIVING** und ` **DIRIVNG_VALUE** , von lokal statischen Untertypen, die einen Funktionsaufruf darstellen, in dem die aktuellen Parameter jeweils lokal statische Ausdrücke sind. * Benutzerdefinierte Attribute, deren Werte durch lokal statische Ausdrücke definiert werden. * Qualifizierte Ausdrücke, deren Ergebnisse lokal statische Untertypen sind und deren Operanden lokal statische Ausdrücke sind. * Eine Typenkonversion dessen Ausdruck lokal statisch ist. * Lokale statische Ausdrücke, die in Klammern gefaßt sind. Ein Ausdruck ist genau dann //global statisch// (nicht dynamisch elaboriert), wenn jeder Operator in diesem Ausdruck eine reine Funtion ist und jedes Primary in diesem Ausdruck ein //global static Primary// ist; als //global static Primaries// gelten: * Werte vom Typ **TIME** . * Lokal statische Primaries * Generische Konstanten * Generische Parameter * Konstanten, inklusive verschobene [[.:constant declarations|(deferred) Konstanten]]. * Aliases, dessen Name ein global statisches Primary ist. * Feld-Aggregate von global statischen Untertypen, deren Elemente nur aus global statischen Ausdrücken bestehen und deren Elemente nur global statische Bereiche (ranges) haben. * Record-Aggregate, dessen Elemente alle global statische Ausdrücke sind. * Funktionsaufrufe, deren Namen eine reine Funktion darstellen und deren aktuelle Parameter jeweils global statische Ausdrücke sind. * Vordefinierte Attribute, welchen einen Wert darstellen und dessen Prefix entweder ein global statischer Untertyp ist oder ein Objekt oder Funktionsaufruf, die von einem global statischen Untertyp sind. * Vordefinierte Attribute, welche eine Funktion außer `EVENT, `ACTIVE, `LAST_EVENT, `LAST_ACTIVE, `LAST_VALUE, `DRIVING oder `DRIVING_VALUE darstellen, dessen Prefix entweder ein global statischer Untertyp ist oder ein Objekt oder Funktionsaufruf, die von einem global statischen Untertyp sind, und dessen tatsächlichen Parameter (falls vorhanden) global statische Ausdrücke sind. * Benutzerdefinierte Attribute, deren Werte durch global statische Ausdrücke definiert werden. * Qualifizierte Ausdrücke, dessen Operand ein global statischer Ausdruck ist. * Typenkonvertierung, dessen Ausdruck eine global statischer Ausdruck ist. * Ein Zeiger der ersten Form (See [[.:allocator|Allocator]]) dessen Untertypekennzeichnung einen global statischen Untertypen bezeichnet. * Ein Zeiger der zweiten Form, dessen qualifizierter Ausdruck ein global statischer Ausdruck ist. * Global statische Ausdrücke, die in Klammern gefaßt sind. * Ein Unterelement oder ein Feldausschnitt eines global statischen Primary, vorrausgesetzt, daß jeder Indexausdruck global statisch Ausdrücke sind und jeder diskrete Bereich des entsprechenden Feldausschnitts global statische diskrete Bereiche sind. ==== Anmerkungen ==== An Stellen wo nur "statisch" steht, kann lokal oder global statisch eingesetzt werden. Die Regeln für lokal und global statische Ausdrücke implizieren, daß eine Konstante oder auch ein Generic mit einem nichtstatischen Ausdruck initialisiert werden können; die Konstante selber kann aber trotzdem lokal oder global statisch sein. Nur für Schnittstellenbkonstanten, Variablen und Signaldeklarationen gilt, daß ein vorhandener Initialisierungsausdruck lokal oder global statisch sein muß. ===== Universeller Ausdruck ===== ==== Definition ==== Ein universeller Ausdruck ist ein Ausdruck, der als Ergebnis entweder den Typ //universal integer// oder //universal real// liefert. ==== Übersicht ==== ^ Operator ^ Operation ^ Typ des linken Operanden ^ Typ des rechten Operanden ^ Typ des Ergebnisses ^ | * | Multiplikation | universal_real | universal_integer | universal_real | | ::: | ::: | universal_integer | universal_real | universal_real | | / | Division | universal_real | universal_integer | universal_real | ====== Sequentielle Anweisungen ====== ===== Wait ===== ==== Anmerkungen ==== Die WAIT-Anweisung darf nicht innerhalb einer Funktion oder einer Prozedur verwendet werden, die selbst innerhalb einer Funktion aufgerufen wird. Die WAIT-Anweisung darf nicht von einem Prozess, der eine 'sensitivity list' besitzt, aufgerufen werden. Im allgemeinen ist die WAIT-Anweisung sensitiv auf die benutzten Signale, außer es wird explizit eine Sensitivityliste angegeben (Wie dies bei der WAIT ON Anweisung der Fall ist; siehe letztes Beispiel). In einem postponed process kann die Bedingung innerhalb einer WAIT Anweisung schon wieder unwahr sein, wenn der Prozeß dann tatsaechlich weiter abgearbeitet wird (eben erst im letzten Delat Zyklus). ==== Beispiele ==== Der Prozess wird auf Dauer unterbrochen. WAIT ; ---- Der Prozess wird für 5 ns unterbrochen. WAIT FOR 5 ns ; ---- Der Prozess wird solange unterbrochen, bis sich der Wert eines der beiden Signale ändert. WAIT ON sig_1, sig_2 ; ---- Der Prozess wird solange unterbrochen, bis ein Ereignis an clock auftritt und der Wert von //clock// gleich 1 ist. WAIT UNTIL clock = '1' ; ---- Der Prozess wird solange unterbrochen, bis der Wert von //data// gleich //good// ist oder 25 ns vergangen sind. WAIT UNTIL data = good FOR 25 ns ; ---- Hier wird zunächst auf eine Änderung einer der Signale sig_1, sig_2, sig_3 gewartet; besitzt clock den Wert 1, wird der Prozeß reaktiviert. Die maximale Unterbrechungsdauer ist 25 ns. WAIT ON sig_1, sig_2, sig_3 UNTIL clock = '1' FOR 25 ns ; ===== Assertion ===== ==== Anmerkungen ==== Der **REPORT** Ausdruck muß vom Typ string sein. Wird der **REPORT** Part weggelassen, so wird der vorgegebene Ausdruck "Assertion violation" verwendet. Der **SEVERITY** Ausdruck muß vom Typ severity_level sein. Mögliche Werte sind: note, warning, error, failure. Wird der **SEVERITY** Part weggelassen, wird der vorgegebene Ausdruck error verwendet. ==== Beispiele ==== Es wird überprüft, ob //signal_reset// ungleich //1// ist. ASSERT signal_reset = '1' ; ---- Wenn //variable_reset// ungleich //1// ist, wird die Meldung "Reset ist aktiv !" ausgegeben. ASSERT variable_reset = '1' REPORT "Reset is active !" ; ---- Wenn die zu überprüfende Bedingung nicht erfüllt ist wird eine Fehlermeldung ausgegeben und entsprechend der Severity-Stufe Aktionen durchgeführt. ASSERT reset = '1' OR set = '1' REPORT "Reset and Set" & "simultaneously active !" SEVERITY failure ; ---- Wenn //data// ungleich //0// ist, wird nur eine Fehlermeldung ( **SEVERITY** note) mit dem aktuellen Wert von //data// ausgegeben. ASSERT data = 0 REPORT "Datum ist gleich " & integer_to_string( data ) & " !" SEVERITY note ; ---- Diese Assertion führt automatisch (wegen false) zum Ende der Simualtion (Severitylevel=failure), wenn sie ausgeführt wird. ASSERT false REPORT "End of simulation!" SEVERITY failure ; ===== Report ===== ==== Anmerkungen ==== Der **REPORT** Ausdruck muß vom Typ string sein. Der **SEVERITY** Ausdruck muß vom Typ severity_level sein. Mögliche Werte sind: note, warning, error, failure. Wird der **SEVERITY** Part weggelassen, wird der vorgegebene Ausdruck note verwendet. ==== Beispiele ==== Dieser Report führt zum Ende der Simualtion (Severitylevel=failure), wenn sie ausgeführt wird. REPORT "End of simulaion!" SEVERITY failure ; ---- Dieser Report meldet das Betreten eines Prozesses. REPORT "Entering process clkdiv" ; ===== Signalzuweisung ... <= ..." ===== ==== Ergänzungen ==== Das Schlüßelwort **unaffected** darf nur in nebenläufigen Signalzuweisungen auftauchen. Voreingestellter Verzögerungsmechanismus ist **inertial** . Beim **transport** Verzögerungsmechanismus werden alle Pulse durchgelassen Beim **inertial** Verzögerungsmechanismus werden nur Pulse durchgelassen, die breiter als eine vorgegeben Grenze sind. Diese Grenze wird durch den Wert nach **reject** oder den ersten Zeitwert in der Waveform bestimmt. Der Wert hinter **reject** darf nicht größer als der erste Zeitwert der Waveform sein. ==== Beispiele ==== Der Wert von //B// wird nach 5 ns dem Signal //A// zugewiesen. Im ersten Fall wird das InertialVerzögerungsmodell verwendet, im zweiten Fall das Transportverzögerungsmodell. A <= B AFTER 5 ns; A <= TRANSPORT B AFTER 5 ns; ---- Dem Signal //data// wird eine Waveform zugewiesen, nach der //data// nach 1 ns den Wert //2// , nach 3 ns den Wert //4// und nach 8 ns den Wert //10// erhält. data <= 2 AFTER 1 ns, 4 AFTER 3 ns, 10 AFTER 8 ns; ---- Dem Signal A wird jeweils mit dem Inertialverzögerungsmodell das Ergebnis der Funktion //my_function// zugewiesen. Dies geschieht bei der ersten Variante nach 5 ns, bei der zweiten und dritten Variante nach einer Zeit, die durch die Konstante delay festgelegt wird. Bei der dritten Variante wird 2 ns nach der vorhergehenden Zuweisung der Wert //0// an A übergeben. A <= my_function(data, 4) AFTER 5 ns; A <= my_function(data, 4) AFTER delay; A <= my_function(data, 4) AFTER delay, 0 AFTER delay + 2 ns; ---- Diese Zuweisungen sind alle equivalent. Der Wert von //input// wird mit 6 ns Verzögerung an //output// weitergegeben. Pulse kleiner 6 ns werden unterdrückt. ouptut <= input AFTER 6 ns; output <= INERTIAL input AFTER 6 ns; output <= REJECT 6 ns INERTIAL input AFTER 6 ns; ---- Hier ist die Pulsbreite anders als der erste Zeitwert der Waveform. So werden alle Signale mit einer Pulsbreite kleiner 3 ns unterdrückt. output1 <= REJECT 3 ns INERTIAL input1 AFTER 6 ns; output2 <= REJECT 3 ns INERTIAL input2 AFTER 6 ns, NOT input2 AFTER 12 ns; ---- Die Signalzuweisungen an //output1// und //output2// sind equivalent den Zuweisungen an //output3// und //output4// . Keine Signalpulse werden unterdrückt. output1 <= TRANSPORT input1 AFTER 6 ns; output2 <= TRANSPORT input2 AFTER 6 ns, NOT input2 AFTER 12 ns; output3 <= REJECT 0 ns INERTIAL input1 AFTER 6 ns; output4 <= REJECT 0 ns INERTIAL input2 AFTER 6 ns NOT input2 AFTER 12 ns; ---- In VHDL'87 mußte die obere Form der Signalzuweisungen gewählt werden. Die beiden Zuweisungsvarianten equivalent. -- VHDL'87 sig2 <= input AFTER 3 ns; output <= TRANSPORT sig2 AFTER 9 ns; -- VHDL'93 output <= REJECT 3 ns INERTIAL input AFTER 12 ns; ===== Variablenzuweisung ... := ..." ===== ==== Beispiele ==== //var// erhält den Wert //0// . var := 0; ---- //a// erhält den aktuellen Wert von //b// . a := b; ---- //a// erhält als neuen Wert das Ergebnis der Funktion //my_function// . a := my_function ( data, 4 ); ---- //str_a// wird ein String zugewiesen, der aus drei verknuepften Teilen besteht. str_a := "Mein Name ist " & get_name & ", und Ihrer ?"; ---- //var_int// erhält als Wert das Ergebnis der rechten Gleichung. var_int := my_function( data, 4 ) + 4 * a_function(var_int) - 2 ** data; ===== Prozeduraufruf ===== ==== Beispiele ==== Die Prozedur //a_proc// wird aufgerufen; sie besitzt keine Übergabeparameter. a_proc ; ---- Die Prozedur //my_proc// wird mit den Übergabeparametern //sig_1// , //sig_2// , //var_3// aufgerufen. my_proc( sig_1, sig_2, var_3 ) ; ---- Die Prozedur //another_proc// wird mit den Übergabe- parametern //var_1// , //var_2// , //q// aufgerufen. another_proc( var_1, var_2, q => const_3 ) ; ---- Die Prozedur //register_proc// wird mit den explizit über Namen zugewiesenen Übergabeparametern //ck// , //d// , //q// aufgerufen. register_proc( ck => clock, d => reg_in, q => reg_out ) ; ===== IF ===== ==== Beispiele ==== Besitzt //a// den Wert //1// , so wird //b// der Wert //0// zugewiesen. IF a = '1' THEN b := '0' ; END IF ; ---- Ist der Wert von //a// größer als //0// , erhält //b// den Wert von //a// , ansonsten den Wert von **ABS** ( //a + 1// ). IF a > 0 THEN b := a ; ELSE b := ABS ( a + 1 ) ; END IF ; ---- Dies ist ein Beispiel für eine komplette **IF** - **ELSIF** -Schleife. Die Bedingungen werden nacheinander überprüft. Bei der ersten Übereinstimmung werden die zugehörigen Aktionen ausgeführt und danach die **IF** -Schleife verlassen. IF val >= 5 AND val < 10 THEN int := 7 ; ELSIF val < 5 THEN int := val + func( val + 2 ) ; ELSIF val < 15 THEN int := func( val ) ; ELSE int := 0 ; END IF ; ===== CASE ===== ==== Beispiele ==== Der Wert des Bits //a// wird überprüft. Ist er //0// , wird //s// der Wert //0000// nach 2 ns zugewiesen, ansonsten der Wert //1111// , ebenfalls nach 2 ns. CASE a IS WHEN '0' => s <= "0000" AFTER 2 ns ; WHEN '1' => s <= "1111" AFTER 2 ns ; END CASE ; ---- Der Wert des Integers //int_value// wird überprüft. Ist er //0// , wird int der Wert //5// zugewiesen, ist er //1// , //2// oder //8// , bekommt int den Wert von //int_value// , ist er zwischen //3// und //7// bekommt int den Wert //int_value + 5// , ist er //9// , dann wird keine Aktion ausgeführt. Für alle anderen Werte von //int_value// wird //int// der Wert //0// zugewiesen. CASE int_value IS WHEN 0 => int := 5 ; WHEN 1 | 2 | 8 => int := int_value ; WHEN 3 TO 7 => int := int_value+5; WHEN 9 => NULL ; WHEN OTHERS => int := 0 ; END CASE ; ---- Abhängig vom Wert des Ausdrucks //two_bit '( a_enable & b_enable )// wird //s// der entsprechchende Wert nach einer bestimmten Zeitverzögerung zugewiesen. CASE two_bit'( a_enable & b_enable ) IS WHEN "00" => s <= zero AFTER 1 ns ; WHEN "10" => s <= a AFTER 1 ns ; WHEN "01" => s <= b AFTER 2 ns ; WHEN "11" => s <= one AFTER 1 ns ; END CASE ; ===== LOOP ===== ==== Beispiele ==== Dies ist eine Endlosschleife, in der bei Erfüllen der Bedingung //clock='1'// dem Signal //q// der Wert von //d// nach 1 ns zugewiesen wird. LOOP WAIT UNTIL clock = '1' ; q <= d AFTER 1 ns ; END LOOP ; ---- Diese mit einem Label versehene Schleife wird sechs mal durchlaufen, wobei der Wert von var jeweils um 5 erhöht wird. lbl : FOR i IN 0 TO 5 LOOP var := var + 5 ; END LOOP ; ---- Die While-Schleife wird durchlaufen, solange //value > 0// gilt. Die Anweisungen innerhalb der Schleife werden für den Fall //value = 3// übersprungen. WHILE value > 0 LOOP NEXT WHEN value = 3 ; tab( value ) := value REM 2 ; value := value / 2 ; END LOOP ; ---- Dies sind zwei Beispiele für verkettete **FOR** -Schleifen, die zur Berechnung der Werte der Elemente eines zweidimensionalen Feldes benötigt werden. In der zweiten Variante besitzen die **FOR** -Schleifen jeweils ein eigenes Label. Mit der **EXIT** -Anweisung wird die innere Schleife verlassen, wenn //i = j// gilt. FOR i IN 10 DOWNTO 2 LOOP FOR j IN 0 TO i LOOP table( i, j ) := i + j - 7 ; END LOOP ; END LOOP ; lbl_1 : FOR i IN 10 DOWNTO 2 LOOP lbl_2 : FOR j IN 0 TO i LOOP EXIT lbl_2 WHEN i = j ; table ( i, j ) := i + j - 7 ; END LOOP lbl_2 ; END LOOP lbl_1 ; ===== NEXT ===== ==== Beispiele ==== In beiden Beispielen werden die Anweisungen nach der **NEXT** -Anweisung ignoriert, wenn //value = 3// gilt. In der ersten Variante wird dies durch eine bedingte **NEXT** -Anweisung erreicht, während in der zweiten Variante eine unbedingte **NEXT** -Anweisung in eine **IF** -Schleife eingebaut worden ist. WHILE value > 0 LOOP NEXT WHEN value = 3 ; tab( value ) := value REM 2 ; value := value / 2 ; END LOOP ; WHILE value > 0 LOOP IF value = 3 THEN NEXT ; END IF ; tab( value ) := value REM 2 ; value := value / 2 ; END LOOP ; ---- Dies sind zwei Beispiele für verkettete **FOR** -Schleifen, die zur Berechnung der Werte der Elemente eines zweidimensionalen Feldes benötigt werden. In der ersten Variante werden für //i = j// die nachfolgenden Anweisungen der inneren Schleife übergangen. In der zweiten Variante wird für //i = j// mit dem nächsten Durchlauf der äußeren Schleife weitergemacht. lbl_1 : FOR i IN 10 DOWNTO 2 LOOP lbl_2 : FOR j IN 0 TO i LOOP NEXT lbl_2 WHEN i = j ; table ( i, j ) := i + j - 7 ; END LOOP lbl_2 ; END LOOP lbl_1 ; lbl_1 : FOR i IN 10 DOWNTO 2 LOOP lbl_2 : FOR j IN 0 TO i LOOP NEXT lbl_1 WHEN i = j ; table ( i, j ) := i + j - 7 ; END LOOP lbl_2 ; END LOOP lbl_1 ; ===== EXIT ===== ==== Beispiele ==== In beiden Beispielen werden die Schleifen mit der **EXIT** -Anweisung verlassen, wenn //value = 0// gilt. In der ersten Variante wird dies durch eine bedingte **EXIT** -Anweisung erreicht, während in der zweiten Variante eine unbedingte **EXIT** -Anweisung in eine **IF** -Schleife ein-gebaut worden ist. LOOP EXIT WHEN value = 0 ; tab( value ) := value REM 2 ; value := value / 2 ; END LOOP ; LOOP IF value = 0 THEN EXIT ; END IF ; tab( value ) := value REM 2 ; value := value / 2 ; END LOOP ; ---- Dies sind zwei Beispiele für verkettete **FOR** -Schleifen, die zur Berechnung der Werte der Elemente eines zweidimensionalen Feldes benötigt werden. In der ersten Variante wird für //i = j// die innere Schleife verlassen. In der zweiten Variante wird für //i = j// die äußere Schleife verlassen. lbl_1 : FOR i IN 10 DOWNTO 2 LOOP lbl_2 : FOR j IN 0 TO i LOOP EXIT lbl_2 WHEN i = j ; table ( i, j ) := i + j - 7 ; END LOOP lbl_2 ; END LOOP lbl_1 ; lbl_1 : FOR i IN 10 DOWNTO 2 LOOP lbl_2 : FOR j IN 0 TO i LOOP EXIT lbl_1 WHEN i = j ; table ( i, j ) := i + j - 7 ; END LOOP lbl_2 ; END LOOP lbl_1 ; ===== RETURN ===== ==== Anmerkung ==== Ein Funktionskörper muß eine **RETURN** -Anweisung beinhalten. Nach der BNF Definition des Prozeßes wird auch hier jede sequentielle Anweisung zugelassen, allerdings wird eine **RETURN** Anweisung in Prozessen nicht von Tools unterstützt. ==== Beispiele ==== Es wird kein Wert zurückgegeben. RETURN ; ---- Rückgabewert ist der von //value// . RETURN value ; ---- Rückgabewert ist das Ergebnis der Funktion //my_function// . RETURN my_function( data, 5 pF ) ; ---- Rückgabewert ist die Summe //a + b + 5 ns// . RETURN a + b + 5 ns ; ---- Rückgabewert ist ein verknüpfter String. RETURN "author name : " & name ; ===== NULL ===== ==== Beispiel ==== Durch die **NULL** -Anweisung wird explizit erwirkt, daß keine Aktion ausgeführt wird. NULL ; ====== Nebenläufige Anweisungen ====== ===== Block ===== ==== Beispiele ==== Dieser einfache Block besitzt einen Label und im Anweisungsteil eine verzögerte Signalzuweisung. b : BLOCK BEGIN s <= '1' AFTER 2 ns ; END BLOCK b ; ---- Diese Block besitzt zusätzlich einen Header, in dem das Signal //int// deklariert wird. c : BLOCK SIGNAL int : bit_vector( 1 TO 3 ) := "010" ; BEGIN s <= int AFTER 5 ns ; END BLOCK c ; ---- In diesem Block wird eine kontrollierte Signalzuweisung verwendet. Ist die Bedingung //clock = '1'// nicht erfüllt, so wird die Signalzuweisung nicht ausgeführt. latch : BLOCK ( clock = '1' ) BEGIN latch_output <= GUARDED latch_input AFTER 1 ns ; END BLOCK latch ; ---- Dieser Block besitzt eigenständige Ein-/Ausgänge, die über die **PORT MAP** mit den übergeordneten Signalen verbunden werden. lbl : BLOCK PORT ( a, b : INOUT bit ) ; PORT MAP ( a => s1, b => s2 ) ; BEGIN b <= a AFTER 1 ns ; a <= b AFTER 1 ns ; END BLOCK lbl ; ===== Prozeß ===== ==== Anmerkungen ==== Alternativ zur Sensitivity-List nach dem Schlüsselwort **PROCESS** kann am Ende des Prozesses folgende Wait Anweisung stehen: **WAIT ON** sensitivity_list ; Ein Prozeß darf nur eine Sensitivity-List **ODER** eine bzw. mehrere explizite WAIT-Anweisungen enthalten. Eine **PROCESS** -Anweisung innerhalb eines **ENTITY** -Anweisungsteiles muß eine passive **PROCESS** -Anweisung sein. Ein Prozeß mit dem Schlüsselwort **POSTPONED** wird als "Postponed Process" bezeichnet. Dieser wird immer (soweit nur ein postponed process existiert) im letzten Delta Zyklus eines Simulationszykluses abgearbeitet. Dies schließt ein, daß also gegebenenfalls nur Signalzuweisungen mit Verzögerungen erlaubt sind (Ansonsten könnten noch weitere Prozesse in nachfolgenden Delta Zyklen abgearbeitet werden). ==== Beispiele ==== Dieser Prozeß beschreibt ein FlipFlop. Durch die **WAIT** -Anweisung und die Überprüfung der Bedingung //clock = '1'// wird die positive Takflanke detektiert. 2 ns nach der Taktflanke liegt am Ausgang //q// der Wert vom Eingang //d// an. PROCESS BEGIN IF ( clock = '1' ) THEN q <= d AFTER 2 ns ; END IF ; WAIT ON clock ; END PROCESS ; ---- Dieser benamte Prozeß beschreibt ebenfalls ein FlipFlop. Durch die Sensitivity-List und die Überprüfung der Bedingung //clock = '1'// wird die positive Takflanke detektiert. 1 ns nach der Taktflanke liegt am Ausgang //q// der Wert vom Eingang //d// an. reg : PROCESS ( clock ) BEGIN IF clock = '1' THEN q <= d AFTER 1 ns ; END IF ; END PROCESS reg ; ---- Dies ist ein Beispiel für einen passiven Prozeß. Mit der positiven Takflanke wird nur die Bedingung //reset = '1'// überprüft und gegebenenfalls eine Warnung ausgegeben. passive : PROCESS BEGIN WAIT ON clock ; IF clock = '1' THEN ASSERT reset = '1' ; REPORT "reset is active!" ; SEVERITY warning ; END IF ; END PROCESS passive ; ---- Dieser Prozeß beinhaltet zwei **WAIT** - Anweisungen. Die erste **WAIT** -Anweisung bewirkt eine Unterbrechung, bis //sig_2 = 0// ist, während die zweite **WAIT** -Anweisung ein Warten auf eine Veränderung einer der beiden Signal //sig_1// oder //sig_2// bewirkt. PROCESS VARIABLE v1, v2 : integer := 1 ; BEGIN sig_1 <= v1 AFTER 1 ns ; WAIT UNTIL sig_2 = 0 ; v2 := v2 * 2 ; v1 := v2 + 4 ; sig_1 <= v1 AFTER 1 ns ; WAIT ON sig_1, sig_2 ; FOR i IN 1 TO 3 LOOP v1 := v1 + v2 ; END LOOP ; END PROCESS ; ---- Ein postponed process, der ein Signalwert übeprüfen soll, wird definiert. POSTPONED PROCESS (testsig) BEGIN ASSERT testsig=expected_value REPORT "testsig differs from" & "expected value!" SEVERITY error ; END POSTPONED PROCESS ; ===== Nebenläufiger Prozeduraufruf ===== ==== Anmerkungen ==== Für jeden nebenläufigen Prozeduraufruf gibt es einen equivalenten Prozeß. Der equivalente Prozeß eines nebenläufigen Prozedurausrufs mit dem Schlüßelwort **POSTPONED** ist ein postponed process. Ein nebenläufiger Prozeduraufruf innerhalb eines **ENTITY** -Anweisungsteiles muß ein passiver nebenläufiger Prozeduraufruf sein. ==== Beispiele ==== Prozeduraufruf ohne Übergabeparamter. a_proc ; ---- Benamter Prozeduraufruf mit über Position verbundenen Übergabeparametern. lab : my_proc( sig_1, sig_2, sig_3 ) ; ---- Prozeduraufruf mit über explizite Zuweisung verbundenen Übergabeparametern. register_proc( ck => clock, d => reg_in, q => reg_out ) ; ---- Prozeduraufruf mit Übergabeparametern, die über Position oder explizite Zuweisung verbunden werden. another_proc( sig_1, sig_2, q => sig_3); ---- Dieses Beispiel verdeutlicht, daß ein nebenläufiger Prozeduraufruf gleich einem Prozeß ist, der als Anweisungsteil nur den Aufruf der Prozedur enthält. check_timing( tplh, tphl, clk, d, q ) ; -- concurrent procedure call PROCESS -- corresponding process BEGIN check_timing( tplh, tphl, clk, d, q); WAIT ON clk, d, q ; END PROCESS ; ===== Nebenläufige Assertion ===== ==== Anmerkungen ==== Für jede nebenläufige Assertion gibt es einen equivalenten (passiven) Prozeß. Der equivalente (passive) Prozeß einer nebenläufigen Assertion mit dem Schlüßelwort **POSTPONED** ist ein postponed process. Besitzt eine nebenläufige Assertion eine statische Bedingung, so wird die Assertion nur ein einziges mal zu Begin der Simulation ausgeführt. ==== Beispiele ==== Dies sind unterschiedliche Beispiele für Assertions. Es wird immer eine Bedingung überprüft ( **ASSERT** ) und gegebenfalls bei Nichterfüllung eine Meldung ( **REPORT** ) ausgegeben. Der SeverityLevel bestimmt, welche Aktionen ausgeführt werden, wenn die zu überprüfende Bedingung nicht erfüllt wird. ASSERT reset = '1' ; ASSERT reset = '1' REPORT "Reset ist aktiv !" ; lbl : ASSERT reset = '1' REPORT "Reset ist aktiv !" SEVERITY warning ; latch_check : ASSERT reset = '1' OR set = '1' REPORT "Reset und Set sind" & "gleichzeitig aktiv !" SEVERITY failure ; lbl : ASSERT data = 0 REPORT "Datum ist gleich " & integer_to_string ( data ) & " !" SEVERITY note ; ===== Nebenläufige Signalzuweisung "... <= ..." ===== ==== Ergänzungen ==== Zu einer bedingten Signalzuweisung existiert eine äquivalente Prozessanweisung, wie dies i.a. für alle nebenläufige Zuweisungen gilt. Der equivalente Prozeß einer nebenläufigen Signalzuweisung mit dem Schlüßelwort **POSTPONED** ist ein postponed process. Hat die bedingte Signalzuweisung die Form target <= options waveform_1 WHEN condition_1 ELSE waveform_2 WHEN condition_2 ELSE . . . waveform_n-1 WHEN condition_n-1 ELSE waveform_n ; dann hat die Signalzuweisung in der zugehörigen Prozessanweisung die Form IF condition_1 THEN target <= wave_transform_1 ; ELSIF condition_2 THEN target <= wave_transform_2 ; . . . ELSIF condition_n-1 THEN target <= wave_transform_n-1 ; ELSE target <= wave_transform_n ; END IF ; Ist die (bedingte) Waveform eine einfache Waveform, so hat die Signalzuweisung in der zugehörigen Prozessanweisung die Form target <= wave_transform ; Die Prozeßanweisung der wave_transform einer waveform der Form waveform_element1, waveform_element1, ..., waveform_elementN besitzt die Form target <= [delay_mechanism] waveform_element1, waveform_element1, ..., waveform_elementN ; Die Prozeßanweisung einer wave_transform einer waveform der Form unaffected besitzt die Form null ; **null** ist hier eine null-Anweisung, keine null-Transaktion! Die Charakteristika der Waveformen und die in der Signalzuweisung enthaltenen Bedingungen müssen so formuliert sein, daß die IF-Anweisung in der zugehörigen Prozessanweisung eine erlaubte Anweisung ist. Zu einer auswählenden Signalzuweisung existiert eine äquivalente Prozessanweisung. Hat die auswählende Signalzuweisung die Form WITH expression SELECT target <= options waveform_1 WHEN choice_list_1 , waveform_2 WHEN choice_list_2 , . . . waveform_n-1 WHEN choice_list_n-1 , waveform_n WHEN choice_list_n ; dann hat die Signalzuweisung in der zugehörigen Prozessanweisung die Form CASE expression IS WHEN choice_list_1 => target <= wave_transform_1 ; WHEN choice_list_2 => target <= wave_transform_2 ; . . . WHEN choice_list_n-1 => target <= wave_transform_n-1 ; WHEN choice_list_n => target <= wave_transform_n ; END CASE ; Zu wave_transform siehe vorhergehenden Punkt zur bedingten Signalzuweisung. Die Charakteristika des Auswahlausdruckes, der Waveformen und die in der Signalzuweisung enthaltene Auswahlbedingungen müssen so formuliert sein, daß die **CASE** -Anweisung in der zugehörigen Prozessanweisung eine erlaubte Anweisung ist. Falls die Option **GUARDED** in der Signalzuweisung enthalten ist, liegt eine sog. kontrollierte Zuweisung vor. Ist hierbei das Zielobjekt (target) ebenfalls kontrolliert, dann lautet der Anweisungsteil der zugehörigen Prozessanweisung wie folgt : IF guard THEN signal_transform ELSE disconnection_statements END IF ; Ist das Zielobjekt (target) nicht kontrolliert, so lautet der Anweisungsteil der zugehörigen Prozessanweisung wie folgt : IF guard THEN signal_transform END IF ; Zuletzt kann der Fall eintreten, daß die Signalzuweisung und das Zielobjekt nicht kontrolliert sind. Dann hat der Anweisungsteil der zugehörigen Prozessanweisung folgendes einfaches Aussehen : signal_transform Es ist nicht erlaubt, eine Signalzuweisung als nicht kontrolliert, das entsprechende Zielobjekt jedoch als kontrolliert zu behandeln ! ==== Beispiele ==== Der Wert von //b// wird nach 5 ns dem Signal //a// zugewiesen. Im ersten Fall wird das Inertialverzögerungsmodell verwendet, im zweiten Fall das Transportverzögerungsmodell. a <= b AFTER 5 ns ; lbl : a <= TRANSPORT b AFTER 5 ns ; ---- Die kontrollierte Signalzuweisung wird nur ausgeführt, wenn die entsprechende Bedingung in der [[.:block|Blockdeklaration]] erfüllt ist. c : data_bus <= GUARDED reg_output AFTER 3 ns ; ---- Gilt //sel=0// , wird //a// nach 5 ns der Wert //1// zugewiesen; gilt //sel=1// , wird //a// nach 3 ns der Wert //0// und nach 5 ns der Wert //1// zugewiesen; ansonsten erhält //a// den Wert //X// nach 2 ns. a <= '1' AFTER 5 ns WHEN sel = 0 ELSE '0' AFTER 3 ns, '1' AFTER 5 ns WHEN sel = 1 ELSE 'X' AFTER 2 ns ; ---- Bei dieser Wertzuweisung an das Signal //sig// wird der Wert von //muxval// berücksichtigt. Gilt //muxval=0// erhält //sig// den Wert //001// usw. Es wird bei dieser Zuweisung unabhängig vom Wert von //muxval// das Verzögerungsmodell **TRANSPORT** verwendet. lmux : WITH muxval SELECT sig <= TRANSPORT "001" AFTER 2 ns WHEN 0 , "110" AFTER 5 ns WHEN 1 , "000" AFTER 5 ns WHEN 2 , "111" AFTER 5 ns WHEN 3 , "XXX" WHEN OTHERS ; ---- //S// wird nur dann mit einem Wert getrieben, wenn der Wert sich vom aktuellen unterscheidet; ansonsten passiert nichts. S <= UNAFFECTED WHEN input = S' DRIVING_VALUE ELSE input AFTER delay ; ===== Komponenteninstantiierung ===== ==== Anmerkungen ==== Im 87'er Standard von VHDL war nur eine Komponenteninstanziierung möglich. Im 93'er Standard ist es nun möglich, eine Entity direkt zu instanziieren oder auch eine Konfiguration einzubinden. Bei der Komponenteninstanziierung muß die entsprechende Komponente vorher deklariert worden sein. Bei der Instanz einer Entity oder Konfiguration muß diese jeweils schon als übersetztes Objekt in einer (für den Compiler sichtbaren) Bibliothek vorhanden sein. ==== Beispiele ==== //my_component// wird in die aktuelle Architecture ohne Port-Map eingebunden. c_1 : my_component ; ---- Die Component //add_n// wird mit dem Generic-Wert //8// instantiiert. Das Signal //s8// wird dabei mit den Ports //Vss// , //a8// , //b8// , //sum// und //sig// mit dem Port //cout// der instantiierten Component verbunden. c : add_n GENERIC MAP (8) PORT MAP ( Vss, a8, b8, sum => s8, cout => sig ) ; ---- Die Entity //my_entity// wird direkt instanziiert. Die Signale //I1// und //I2// der Entity //my_entity// werden mit den lokalen Signalen S1 und S2 verbunden. u_myent: ENTITY work.my_entity(beh) PORT MAP (I1 => S1 , I2 => S2 ) ; ---- Die Konfiguration //my_cfg// wird instanziiert. Die Signale //I1// und //I2// der in der Konfiguration angegeben Entity werden mit den lokalen Signalen S1 und S2 verbunden. u_config: CONFIGURATION work.my_cfg PORT MAP (I1 => S1 , I2 => S2 ) ; ---- //ram_comp// wird instantiiiert und automatisch die Generics //nb_data// und //nb_addr// vorbelegt. Die Signale werden namentlich einander zugewiesen, wobei der port //ready// nicht angeschlossen wird. the_ram : ram_comp GENERIC MAP ( nb_data => 8, nb_addr => 5 ) PORT MAP ( cs => cs, rw => rw, d => data, a => address, ready => OPEN ) ; ---- Dies ist ein Beispiel, das die Zusammenhänge erklären soll. * <- Komponenten-Deklaration * <- Komponenten-Instantiierung mit Verknüpfung der Ports * <- Deklaration der Configuration (Für //comp// soll die Architecture y der Entity x verwendet werden.) * <- Deklaration der Entity (//check_timing// ist eine passive Prozedur!) * <- Deklaration der Architecture COMPONENT comp PORT (a , b : INOUT bit); c : comp PORT MAP ( a => s1, b => s2 ) ; FOR c : comp USE ENTITY x(y) ; PORT MAP ( p1 => a, p2 => b ) ; ... ENTITY x IS PORT ( p1, p2 : INOUT bit ) CONSTANT delay : time := 1 ms ; BEGIN check_timing( p1, p2, 2 * delay ) ; END x ; ARCHITECTURE y OF x IS SIGNAL p3 : bit ; BEGIN p3 <= p1 AFTER delay ; p2 <= p3 AFTER delay ; b : BLOCK ... BEGIN ... END BLOCK ; END y ; Hier der zu dem oberen gleichwertige Code: * <- Komponenten-Block * <- lokale Ports * <- Portverknüpfung * <- Entity-Block * <- formale Ports * <- Portverknüpfung * <- Vereinbarung in der Entity * <- Vereinbarung in der Architecture * <- Entity-Anweisung * <- 2 Architecture-Anweisungen * <- interne Blockhierarchie c : BLOCK PORT ( a, b : INOUT bit ) ; PORT MAP ( a => s1, b => s2 ) ; BEGIN x : BLOCK PORT ( p1, p2 : INOUT bit ) ; PORT MAP ( p1 => a, p2 => b ) ; CONSTANT delay : time := 1 ms ; SIGNAL p3 : bit ; BEGIN check_timing(p1, p2, 2 * delay) ; p3 <= p1 AFTER delay ; p2 <= p3 AFTER delay ; b : BLOCK ... BEGIN ... END BLOCK ; END BLOCK x ; END BLOCK c ; ===== Generateanweisung ===== ==== Anmerkungen ==== In VHDL'87 war kein deklarativer Bereich zugelassen. ==== Beispiele ==== Diese Generate-Anweisung erzeugt eine parallele Kette aus den beiden Komponenten //comp_1// und //comp_2// mit der Länge 5. lbl_1 : FOR i IN 1 TO 5 GENERATE c1 : comp_1 PORT MAP ( ck => clock, d => a(i), q => a(i+1) ) ; c2 : comp_2 PORT MAP ( ck => clock, d => a(i) ) ; END GENERATE ; ---- Wenn das Generic //n// größer 0 ist, so werden die Signalzuweisungen wirksam und die Komponente //my_comp// instantiiert. lbl_2 : IF n > 0 GENERATE sig_1 <= '1' AFTER 5 ns ; sig_2 <= sig_1 AFTER 2 ns ; c : my_comp PORT MAP (a, b, c) ; END GENERATE ; ---- Beispiel für eine verkettete Generate-Anweisung. Innerhalb der äußeren Anweisung werden abhängig von der Zählervariablen //i// verschiedene Komponenten instantiiert. cadd : FOR i IN 1 TO n GENERATE cb : IF i = 1 GENERATE add_b : add_begin PORT MAP ( ... ) ; END GENERATE ; cm : IF i > 1 AND i < n GENERATE add_m : add_middle PORT MAP ( ... ) ; END GENERATE ; ce : IF i = n GENERATE add_e : add_end PORT MAP ( ... ) ; END GENERATE ; END GENERATE cadd ; ---- Beispiel für die weitreichende Einsatzmöglichkeit der Generate-Anweisung. Die verketteten Generate-Anweisungen unter Label //l2// wurden wegen der Übersichtlichkeit unter Label //l6// mit einer veränderten **IF** -Bedingung dupliziert. Die Generate-Anweisung unter Label //l8// kann auch innerhalb der der Generate-Anweisung unter Label //l3// angeführtwerden. b : BLOCK BEGIN l1 : cell PORT MAP ( top, bottom, a(0), b(0) ) ; l2 : FOR i IN 1 TO 3 GENERATE l3 : FOR j IN 1 TO 3 GENERATE l4 : IF i + j > 4 GENERATE l5 : cell PORT MAP ( a(i-1), b(j-1), a(i),b(j)); END GENERATE ; END GENERATE ; END GENERATE ; l6 : FOR i IN 1 TO 3 GENERATE l7 : FOR j IN 1 TO 3 GENERATE l8 : IF i + j < 4 GENERATE l9 : cell PORT MAP ( a(i+1), b(j+1), a(i), b(j)); END GENERATE ; END GENERATE ; END GENERATE ; END BLOCK b ; ====== Verschiedenes ====== ===== Sichtbarkeits- und Gültigkeitsbereiche ===== ==== Deklarationsbereich ==== Deklarative Bereiche sind Teile des Beschreibungstextes. Einzelne, deklarative Bereiche sind: * Entity-Deklarationen, zusammen mit den korrospondierenden Architekturkörpern * Konfigurationsdeklarationen * Unterprogrammdeklarationen, zusammen mit dem korrospondierenden Unterprogrammkörper * Packagedeklarationen, zusammen mit dem korrospondierenden Packagekörper (wenn vorhanden) * Recorddeklarationen * Komponentendeklarationen * Blockanweisungen * Prozeßanweisungen * Loopanweisungen * Blockkonfigurationen * Komponentenkonfigurationen ==== Gültigkeitsbereich einer Deklaration ==== Der Gültigkeitsbereich einer Deklaration erstreckt sich vom Anfang der Deklaration bis zum Ende des deklarative Bereiches, in dem die Deklaration erfolgt; dieser Bereich wird unmittelbarer Bereich genannt. Für folgende Deklarationen erstreckt sich der Gültigkeitsbereich über den entsprechenden deklarativen Bereich hinaus: * Deklarationen, die unmittelbar innerhalb einer Packagedeklaration erfolgen * Elementendeklarationen innerhalb einer Recordtypendeklaration * Deklarationen formaler Parameter innerhalb von Unterprogrammdeklarationen (Unterprogrammspezifikation, falls keine Unterprogrammdeklaration vorhanden) * Deklarationen lokaler Generics innerhalb von Komponentendeklarationen * Deklarationen lokaler Ports innerhalb von Komponentendeklarationen * Deklarationen formaler Generics innerhalb von Entitydeklarationen * Deklarationen formaler Ports innerhalb von Entitydeklarationen Allgemein erstreckt sich der Gültigkeitsbereich auch auf die entsprechende Konfiguration, Deklaration und auf die in dieser enthaltenen Konfigurationen und Deklarationen (Hierarchie). ==== Sichtbarkeit ==== Elemente werden entweder über Selektion sichtbar gemacht oder sind direkt sichtbar. Die Sichtbarkeitsregeln definieren den Bereich, in dem auf ein deklariertes Objekt (Identifier!) zugegriffen werden kann. Auch kann nur eine Deklaration für die Verwendung des Objekts gültig sein (Overloading)., Eine Deklaration wird über eine Selektion an folgenden Stellen sichtbar gemacht: * Für ein Primary Unit in einer Bibliothek: An der Stelle des Suffix in einem selektierten Namen, dessen Prefix eine Bibliothek kennzeichnet. * Für eine Architektur, die mit einer Entity verknüpft ist: An der Stelle einer Blockspezifikation innerhalb einer Blockkonfiguration eines externen Blocks, dessen Schnittstelle durch die aktuelle Entity definiert ist. * Für eine Deklaration innerhalb einer Packagedeklaration: An der Stelle des Suffix in einem selektierten Namen, dessen Prefix ein Package kennzeichnet. * Für eine Elementendeklaration einer gegebenen Recorddeklaration: An der Stelle des Suffix in einem selektierten Namen, dessen Prefix passend für diesen Typ ist; ebenso an der Stelle einer Auswahl in einer Zuweisung über Namen innerhalb eines Aggregats dieses Typs. * Für ein vordefiniertes Attribut, welches zu einem Bereich einer Definition paßt: An der Stelle des Designators in einem Attributnamen, dessen Prefix einem gegebenen Bereich zugeordnet ist. * Für ein benutzerdefiniertes Attribut: An der Stelle des Designators in einem Attributnamen, dessen Prefix eine Entity bezeichnet. * Für eine formale Parameterdeklaration innerhalb einer gegebenen Unterprogrammdeklaration: An der Stelle des formalen Designators in einer Namenszuweisungsliste innerhalb des Unterprogrammaufrufs. * Für eine lokale Genericdeklaration einer gegebenen Komponentendeklaration: An der Stelle des formalen Designators in einer Generic-Namenszuweisungsliste der korrespondierenden Komponentenistantiierung; gleichfalls an der Stelle des aktuellen Designators in einer Generic-Namenszuweisungsliste der korrespondierenden Einbindung. * Für eine lokale Portdeklaration einer gegebenen Komponentendeklaration: An der Stelle des formalen Designators in einer Port-Namenszuweisungsliste der korrespondierenden Komponeteninstantiierung; gleichfalls an der Stelle des aktuellen Designators in einer Port-Namenszuweisungsliste der korresponmdierenden Einbindung. * Für eine lokale Genericdeklaration einer gegebenen Entitydeklaration: An der Stelle des formalen Designators in einer Generic-Namenszuweisungsliste der korrespondierenden Einbindung. * Für eine formale Portdeklaration einer gegebenen Entitydeklaration: An der Stelle des formalen Designators in einer Port-Namenszuweisungsliste der korrespondierenden Einbindung. * Für eine formale Generic- oder Portdeklaration einer gegebenen Blockanweisung: An der Stelle des formalen Designators im formalen Teil einer Namenszuweisung der entsprechenden Generic- oder Portabbildung. Letztlich wird jede Deklaration, die innerhalb des Deklarationsbereiches eines beliebigen Konstrukts (außer eines Records) steht, als Suffix eines expanded name sichtbar, wobei das Prefix obiges Konstrukt markiert. z.B. in einer Konfiguration : USE ENTITY WORK.tv(SAT1) Prefix.Suffix wie 1. Rom cell(0) <= ROMBIB.rom_package.constant(0) date.month <= "April" date <= (Year => 1997, Day => 9, Month => "April") ; ASSERT ack`STABLE(setup_time) REPORT "setup time violation by Ack" SEVERITY WARNING ATTRIBUTE author OF tb_i2c : ENTITY IS "Martin Padeffke" FUNCTION ksc_fans(Number) RETURN INTEGER ; ARCHITECTURE einschaltquoten OF tv IS BEGIN ... pot_viewers <= ksc_fans(football_fans) + ... END einschaltquoten ; UUT : bus_monitor GENERIC MAP ( setup_time => setup, clock_period => clk_period , ... ) ; PORT MAP ( bus => scd, takt => scl, ...) ; wie 8. wie 9. wie 8. bzw. wie 9. ==== Direkte Sichtbarkeit ==== Eine beliebige Deklaration ist in ihrem unmittelbaren Gültigkeitsbereich direkt sichtbar (Ausnahme: versteckte Deklaration) : Deklarationen eines Packages können über [[.:Use-statements|Use Anweisungen]] direkt sichtbar gemacht werden. Eine Deklaration heißt //hidden// , wenn sie durch eine lokale Deklaration überdeckt wird - wie im Beispiel. Ausnahme: Overloading - mehrere Deklarationen mit gleichem Identifier existieren nebeneinander und aus dem Zusammenhang des Aufrufs wird die passende ausgewählt ([[.:Use-statements|Auflösung von Überladungen]]). Das Signal //b// wird in Block //lbl_1// und in Block //lbl_2// deklariert. Wird //b// ohne weitere Kennzeichnung angesprochen, so ist das 'innere' Signal gemeint. Ansonsten ist dies explizit durch Voranstellen des entsprechenden Labels zu kennzeichnen. lbl_1 : BLOCK SIGNAL a, b : bit ; BEGIN lbl_2 : BLOCK SIGNAL b : bit ; BEGIN a <= b AFTER 5 ns ; -- Equivalent: <- lbl_1.a <= lbl_2.b AFTER 5 ns b <= lbl_1.b AFTER 10 ns ; -- Equivalent: <- lbl_2.b <= lbl_1.b AFTER 10 ns END BLOCK lbl_2 ; b <= a AFTER 15 ns ; -- Equivalent: <- lbl_1.b <= lbl_1.a AFTER 15 ns END BLOCK lbl_1 ; ===== Use Anweisungen ===== ==== Anmerkung ==== Die **USE** -Anweisung kann auch als Kontext-Anweisung vor jedem Bibliothekenbaustein, d. h. entity, architecture, package, package body und configuration, gestellt werden. ==== Beispiele ==== Alle Packages aus der Default-Biblitohek //work// werden eingebunden. USE work. ALL ; ---- Alle Elemente des Package //my_package// aus der Bibliothek //work// werden eingebunden. USE work.my_package. ALL ; ---- Die Funktion //my_function// aus dem Package //my_package// in der Biblitohek //work// wird eingebunden. USE work.my_package.my_function ; ---- Aus den Packages //pkg_1// und //pkg_3// werden alle Elemente eingebunden; vom Package //pkg_2// wird nur die Prozedur //proc_1// eingebunden. USE lib_1.pkg_1. ALL , lib_1.pkg_2.proc_1, lib_2.pkg_3. ALL ; ==== Auflösung von Überladungen ==== Das Überladen ist für [[.:Overloading|Unterprogramme, Operatoren]] und [[.:Scalar types|Werte von Aufzählungstypen]] definiert. Unter Überladung versteht man die gleichzeitige [[.:Visibility and validity ranges|Sichtbarkeit]] von mehreren gleichnamigen Unterprogrammen, Operatoren bzw. von Objektwerten, die zu unterschiedlichen Aufzählungstypen gehören können. Mit Hilfe der Überladung gelingt es beispielsweise, den Anwendungsbereich einer Funktion zu vergrößern. Die verschiedenen Varianten eines Unterprogramms oder eines Operators unterscheiden sich nur in Anzahl und Typ ihrer Argumente und Ergebnisse. VHDL-Programme erkennen aus dem Kontext heraus (d.h. aus der Argumentanzahl und deren Typen), welche der sichtbaren Varianten anzuwenden ist. Ist diese Entscheidung nicht eindeutig, d.h. sollten sich mehrere sichtbare Alternativen als "passend" für die zu erfüllende Aufgabe erweisen, erfolgt die Ausgabe einer Fehlermeldung. Durch das Konzept der Überladung werden VHDL-Modelle übersichtlicher, da nicht für jede Variante einer beestimmten Funktionalität ein neuer Bezeichner vergeben werden muß. ===== Design Units und deren Analyse ===== ==== Anmerkung ==== Die **LIBRARY** -Anweisung ist als Kontext-Anweisung vor jedem Bibliothekenbaustein, d. h. entity, architecture, package, package body und configuration anführbar. ==== Beispiele ==== Verschiedene Bibliotheken werden bekanntgemacht. LIBRARY my_library ; LIBRARY my_library_1, my_library_2 ; ---- Nach Bekanntmachung der Bibliotheken //std// und //work// werden alle Elemente aus dem Package //standard// der Bibliothek //std// eingebunden. LIBRARY std, work ; USE std.standard. ALL ; ====== Elaboration und Simulation ====== Die Elaboration ist für Deklarationen, Entwurfshierarchien sowie Anweisungen (einschließlich nebenläufiger Anweisungen) definiert. Ein Konstrukt wird erst durch den Vorgang der Elaboration wirksam. Vor Beendigung der Elaboration ist das betreffende Konstrukt nicht existent! {{:vhdl_reference_93:vhdlreference_simulationflow.svg?nolink&400|Simulation Flow}} Um ein Modell auszuführen, muß zunächst die Entwurfshierarchie, welche das Modell beschreibt, elaboriert werden. Danach erfolgt die Initialisierung der Netze des Modells, um anschließend die Simulation des Modells zu starten. Diese beinhaltet das mehrmalige Durchlaufen des Simulationszyklus. Dabei werden die Prozesse ausgeführt und die Netzlistenparameter neu berechnet bzw. aktualisiert. ===== Elaboration eines Blockheaders ===== ==== Die Generic-Anweisung ==== {{:vhdl_reference_93:vhdlreference_elaborationblockheadergenericstatement.svg?nolink&300|Elaboration of Generic Statement}} Die Elaboration der in der Generic-Anweisung enthaltenen Generic-Deklarationen erfolgt in der vorgegebenen Reihenfolge. Dabei werden die Untertypen des Generics gebildet, sowie eine Generic-Konstante zu jedem dieser Untertypen bereitgestellt. Der jeweilige Wert wird erst bei der späteren Elaboration nachfolgender Generic-Abbildungsanweisungen ermittelt. Fehlen diese Abbildungsanweisungen, so verwendet das System den der jeweiligen Generic-Konstante zugeordneten Defaultwert. ==== Die Generic-Abbildungsanweisung ==== Hier wird die Generic-Verknüpfungsliste elaboriert. Diese enthält ein implizit definiertes Zuordnungselement für jede nicht explizit zugeordnete Generic-Konstante. GENERIC (explicit_generic : INTEGER := 9); Der zu berechnende Teil des implizit definierten Zuordnungselements ist dabei der in der Deklaration der jeweiligen Auswahl-Konstante enthaltene Ausdruck. {{:vhdl_reference_93:vhdlreference_elaborationblockheadergenericmap.svg?nolink&300|Elaboration of a Generic Map}} Die Elaboration der Listenelemente, die aus einem formalen und einem aktuellen Teil bestehen, erfolgt sequentiell. Der formale Teil einer Generic-Konstanten wird dabei mit den Werten, die bei der Berechnung des entsprechenden aktuellen Teiles entstehen, belegt. ==== Die Port-Anweisung ==== Das System wertet die entsprechenden Port-Deklarationen, die in der Anweisung enthalten sind, in der angegebenen Reihenfolge aus. Die Elaboration einer Port-Deklaration besteht darin, zunächst den Untertyp festzulegen und dann einen Port zu diesem Untertyp zu erzeugen. (vgl. Die Generic-Anweisung ) ==== Die Port-Abbildungsanweisung ==== {{:vhdl_reference_93:vhdlreference_elaborationblockheaderportmap.svg?nolink&300|Elaboration of a Port Map}} Hier wertet das System die Port-Verknüpfungsliste aus. Diese enthält Zuordnungsanweisungen, die dem formalen Ausdruck das im tatsächlichen Ausdruck spezifizierte Signal zuweist. Diese Zuordnung beinhaltet das Prüfen der Regeln und Einschränkungen, die Ports betreffen. Ein gegebener Ausdruck innerhalb einer Port-Deklaration (Initialisierungsanweisung) wird unter Verwendung der tatsächlichen Werte elaboriert. Falls in der Zuordnungsanweisung kein Signal mit diesem Port verknüpft wird und der Port einen Eingang darstellt, erhält dieser einen Defaultwert, sofern für diesen Port ein solcher definiert worden ist. ===== Elaboration einer Deklaration ===== Die Elaboration einer Deklaration entspricht dem Erzeugen des deklarierten Konstrukts. Die syntaktischen Regeln ( hier besonders die Regeln bezüglich des [[.:Visibility and validity ranges|Geltungsbereiches]]) gestatten es nicht, ein Konstrukt vor Elaboration der betreffenden Deklaration zu verwenden. ==== Deklaration von Unterprogrammen und Unterprogrammkörpern ==== Die Elaboration einer Unterprogramm-Deklaration erfolgt durch die Elaboration der zugehörigen Schnittstellen- bzw. Interface- Parameterliste. Dabei wird der Untertyp jedes Schnittstellen-Elements und somit der Untertyp jedes formalen Parameters im Unterprogramm festgelegt. Die Elaboration des Unterprogrammkörpers erlaubt die Nutzung des Unterprogrammes bei späteren (nicht früheren !) Unterprogrammaufrufen. {{:vhdl_reference_93:vhdlreference_elaborationsubprogram.svg?nolink&350|Elaboration of a Subprogram}} ==== Deklaration von Typen ==== {{:vhdl_reference_93:vhdlreference_elaborationtype.svg?nolink&400|Elaboration of a Type}} Das System elaboriert die Definition des Typs und erzeugt danach diesen Typ. Bei einer eingeschränkten Felddeklaration jedoch erfolgt die Elaboration des gleichwertigen unbeschränkten Feldtyps (d.h. Elaboration des Untertyps der Elemente), gefolgt von der Elaboration des betreffenden Untertyps des unbeschränkten Feldtyps. Die Elaboration eines Aufzählungstyps erzeugt den entsprechenden Typ. Bei Integer-, Gleitkomma- oder physikalischen Typdefinitionen werden die entsprechenden Untertypen festgelegt. Bei physikalischen Typdefinitionen erfolgt zusätzlich die Erzeugung der Einheiten. Ein Datensatz (Record-Konstruktion) wird durch Elaboration der Deklarationen ihrer einzelnen Elemente in der angegebenen Reihenfolge elaboriert. (ähnlich wie beim Feldtyp) Die Elaboration einer Elementdeklaration besteht in der Festlegung des Untertyps. Die Elaboration einer Zeiger-Deklaration entspricht der Elaboration des entsprechenden Untertyps. ==== Deklaration von Untertypen ==== Hier erfolgt die Festlegung und Erzeugung des Untertyps. Falls der Untertyp keine Beschränkungen hat, gleicht dieser dem Grundtyp. Sonst wird zunächst die Beschränkung elaboriert und dann ein Kompatibilitätstest hinsichtlich des Grundtyps durchgeführt. {{:vhdl_reference_93:vhdlreference_elaborationsubtype.svg?nolink&450|Elaboration of a Subtype}} Die Elaboration einer Beschränkung des Wertebereiches erfolgt durch Berechnung dieses Wertebereichs. Dabei werden die Wertegrenzen und die Zählrichtung des Bereiches definiert. Eine Größenbeschränkung wird durch die Berechnung des entsprechenden Ausdrucks elaboriert. ==== Deklaration von Objekten ==== Hier ist zu unterscheiden zwischen Datei-Objekten und sonstigen. Bei ersteren erfolgt die Festlegung und anschließende Erzeugung des Untertyps. Der logische Dateiname wird ermittelt sowie die entsprechende physikalische Datei mit dem neuen Objekt verknüpft. Folgender Ablauf gilt fuer alle anderen Arten von Objekten (außer Port- und Generic-Deklarationen): * Der Untertyp des Objekts wird definiert. * Falls die Deklaration des Objekts einen expliziten Initialisierungsausdruck enthält, erfolgt eine Berechnung des Wertes dieses Ausdrucks. Dieser ist dann der Startwert des Objekts. Anderenfalls erhält das Objekt einen implizit definierten Anfangswert. * Das Objekt wird erzeugt. * Der Startwert wird dem Objekt zugewiesen. Das Initialisieren beinhaltet einen Test auf Zugehörigkeit des Startwertes zum Untertyp des Objekts. Bei einem durch eine Objekt-Deklaration bezeichneten Feld-Objekt wird als erster Schritt der Untertyp solange umgewandelt, bis das Objekt eine Konstante ist, dessen Untertyp ein Typ eines uneingeschränkten Feldes ist. Ein Fehler tritt auf, falls die Bezeichnung eines Untertyps des Objekts vor der Elaboration der betreffenden Deklaration verwendet wird. Wird ein File elaboriert, dessen Deklaration keine Öffnungsinformation enthält, wird zuerst implizit FILE-OPEN aufgerufen. ==== Deklaration von Aliases ==== Der mit dem Alias assoziierte Untertyp wird festgelegt und erzeugt. Anschließend wird ein alternativer Name erzeugt. Das Erzeugen eines Alias für ein Feld-Objekt beinhaltet eine Prüfung auf Konsistenz jedes Elements des zu ersetzenden Objekts mit entsprechenden Elementen, die der Alias-Untertyp enthält. {{:vhdl_reference_93:vhdlreference_elaborationalias.svg?nolink&350|Elaboration of an Alias}} ==== Deklaration von Attributen ==== Es wird ein Template erzeugt, mit dem die Definition von Attributen für die jeweiligen Elemente möglich wird. {{:vhdl_reference_93:vhdlreference_elaborationattribute.svg?nolink&500|Elaboration of an Attribute}} ==== Deklaration von Komponenten ==== Das System erzeugt ein Template zur Bildung der Instanzen der Komponente. ==== Elaboration einer Spezifikation ==== Hierbei werden zusätzliche Informationen einem vorher deklarierten Programmteil zugeordnet. ==== Spezifikation von Attributen ==== Die Elaboration läuft folgendermaßen ab: * Die Spezifikation einer Entity wird elaboriert, um feststellen zu können, welche einzelnen Elemente von der Attribut-Spezifikation betroffen sind. * Um den Wert des Attributs festzulegen, wird der Ausdruck ausgewertet. * Eine neue Instanz des Attributes wird erzeugt und mit jedem der davon beeinflußten Programmelemente bzw. -punkte verbunden. * Jede neue Instanz des Attributes erhält den Wert des Ausdrucks. Die unter 4. beschriebene Zuweisung beinhaltet einen Test auf Zugehörigkeit des Wertes zum Untertyp des Attributes. Bei einem Attribut eines beschränkten Feld-Typs wird als erster Schritt der Untertyp einer impliziten Typkonvertierung unterworfen, wie bei einer Zuweisungsanweisung. Eine solche Konvertierung ist nicht notwendig für unbeschränkte Feld-Typen. ==== Spezifikation von Konfigurationen ==== Die Elaboration läuft folgendermaßen ab: * Die Komponentenspezifikation wird elaboriert, um festzustellen, welche Instanzen der Komponenten von der Konfiguration beeinflußt werden. * Die Bindungs-Festlegung wird elaboriert, um diejenige Entity zu identifizieren, an welche die unter 1. bestimmten Komponenten-Instanzen gebunden werden. * Die Bindungs-Informationen werden mit jeder beeinflußten Komponenten-Instanz verknüpft, damit diese im weiteren Verlauf zur Bildung weiterer Instanzen verwendet werden können. Das beschriebene Verfahren beinhaltet einen Test darauf, daß die Deklaration der Entity und die entsprechende Architecture, die von den Bindungs-Festlegungen impliziert werden, innerhalb der spezifizierten Bibliothek existieren. {{:vhdl_reference_93:vhdlreference_elaborationconfiguration.svg?nolink&600|Elaboration of a Configuration}} ==== Disconnection-Spezifikation ==== Dabei werden folgende Schritte ausgeführt: * Die guarded specification des Signals wird elaboriert, um festzustellen, welche Signale von der Disconnect-Spezifikation beeinflußt werden. * Der Zeit-Ausdruck wird ermittelt, um die Zeit für die Disconnection-time der Treiber der unter 1. ermittelten Signale zu bestimmen. * Die Disconnection-time wird mit jedem beeinflußten Signal verknüpft. Diese kann (in Prozessen für guarded signal-Belegungen) zum Formulieren von Disconnection-Anweisungen genutzt werden. {{:vhdl_reference_93:vhdlreference_elaborationdisconnection.svg?nolink&600|Elaboration of a Disconnection}} ===== Elaboration eines Anweisungsteils ===== Die Elaborationsregeln gelten für alle Anweisungsteile mit Ausnahme einer Architektur, die mit dem Attribut **FOREIGN** versehen ist. Diese werden implementierungsabhängig elaboriert. ==== Anweisungen innerhalb von Blöcken ==== Es erfolgt eine sukzessive Elaboration des * Blockanfangs (falls vorhanden), my_block : BLOCK (enable = '1') PORT (farbe_1, farbe_2, select : std_ulogic; auswahl : std_ulogic BUS); PORTMAP (farbe_1 => color(0), farbe_2 => color(1), auswahl => point); * Block-Deklarationsteils, SIGNAL inter : std_ulogic; * Block-Anweisungsteils. BEGIN inter <= farbe_1 WHEN select = '0' ELSE farbe_2; auswahl <= GUARDED inter; END BLOCK my_block; Die Elaboration einer Block-Anweisung kann unter der Kontrolle einer Konfigurationsdeklaration erfolgen. Eine darin eingeschlossene Blockkonfiguration kann eine Reihe zusätzlicher implizit definierter Spezifikationen erzeugen, die bei der Elaboration der entsprechenden Block-Anweisung verwendet und somit gleichzeitig elaboriert werden. Jede dieser impliziten Spezifikationen besteht aus derjenigen Spezifikation der Konfiguration, die von den Konfigurationen der Komponenten innerhalb der Blockkonfiguration impliziert werden. {{:vhdl_reference_93:vhdlreference_elaborationblockstatement.svg?nolink&700|Elaboration of a Block Statement}} ==== Die Generate-Anweisung ==== Die Generate-Anweisung wird durch Kopien von Blockanweisungen ersetzt, deren Anweisungsteil aus den in der Generate-Anweisung enthaltenen nebenläufigen Anweisungen besteht. Jede Blockanweisung wird anschließend elaboriert. {{:vhdl_reference_93:vhdlreference_elaborationgeneratestatement.svg?nolink&500|Elaboration of a Generate Statement}} Bei einer **FOR** -Generate-Anweisung wird der jeweilige Wertebereich elaboriert. Danach wird eine Blockanweisung zu jedem Wert innerhalb des Bereichs erzeugt. Diese hat folgende Merkmale: * Die Namen der Blockanweisung und der Generate-Anweisung sind gleich. * Der Deklarationsteil enthält eine Konstantendeklaration, die eine Konstante unter dem Namen des Generate-Parameters deklariert. Der Wert der Konstanten entspricht dem des Generate-Parameters, der Typ wird durch den Grundtyp des Wertebereichs des Generate-Parameters bestimmt. * Der Anweisungsteil enthält die Kopie der nebenläufigen Anweisungen aus der Generate-Anweisung. Bei einer **IF** -Generate-Anweisung wird der logische Ausdruck berechnet. Falls der Ausdruck den Wert true annimmt, wird eine Blockanweisung erzeugt. Diese hat folgende Merkmale: * Die Namen des Blocks und der Generate-Anweisung stimmen überein. * Der Deklarationsteil des Blocks ist leer. * Der Anweisungsteil enthält eine Kopie der nebenläufigen Anweisungen (s.o.). ==== Anweisungen zur Komponenteninstantiierung ==== Die Komponente muß entweder voll an eine per Entity-Deklaration und Architecture festgelegte Entity oder an eine Konfiguration einer Entity gebunden sein. Es wird sowohl die implizit definierte Blockanweisung, welche die Instanz der Komponente beschreibt, als auch die ebenfalls implizite, auf die oben erwähnte Entity bezugnehmende Blockanweisung elaboriert. ==== Weitere nebenläufige Anweisungen ==== Alle weiteren nebenläufigen Anweisungen sind entweder Prozess-Anweisungen oder aber solche Anweisungen, für die eine gleichwertige Prozess-Anweisung existiert. Die Elaboration besteht aus folgenden Schritten: * Der Deklarationsteil des Prozesses wird elaboriert. * Die von der Prozess-Anweisung angeforderten Treiber werden bereitgestellt. * Der durch Defaultwerte von skalaren Signalen definierte Anfangsvorgang wird in den entsprechenden Treiber geladen. Die Elaboration aller nebenläufigen Signal-Zuordnungsanweisungen und aller nebenläufigen Assertion-Anweisungen besteht aus der Erzeugung einer gleichwertigen Prozess-Anweisung gefolgt von deren Elaboration. {{:vhdl_reference_93:vhdlreference_elaborationotherconcurrentstatement.svg?nolink&600|Elaboration of other concurrent statement}} ===== Dynamische Elaboration ===== Die Ausführung von Programmteilen, die sequentielle Anweisungen enthalten, erfordert ebenfalls deren Elaboration. Diese erfolgt während der Ausführung des Modells. Als Beispiele, bei denen die Elaboration dynamisch während der Simulation erfolgt, sind folgende zu nennen: * Die Ausführung einer **FOR** -Iterationsschleife beinhaltet die Elaboration der Schleifen-Parameter, bevor die innerhalb der Schleife liegenden Anweisungen ausgeführt werden können. Die Elaboration erzeugt die Schleifen-Parameter und berechnet deren Wertebereiche. {{:vhdl_reference_93:vhdlreference_elaborationloop.svg?nolink&500|Dynamic Elaboration of a FOR loop}} * Die Ausführung eines Unterprogrammaufrufes setzt die Elaboration der Parameter-Schnittstellenliste der entsprechenden Unterprogrammdeklaration voraus. Dabei wird jede Schnittstellen-Deklaration elaboriert, um die formalen Parameter erzeugen zu können. Diese werden dann mit den actual-Parametern verknüpft. Schließlich erfolgt die Elaboration des Deklarationsteils des zugehörigen Unterprogrammkörpers. Die Anweisungsfolge des Unterprogrammkörpers wird ausgeführt. {{:vhdl_reference_93:vhdlreference_elaborationsubprogramparameter.svg?nolink&500|Dynamic Elaboration of a Subprogram}} * Die Berechnung eines Zeigers, der eine Untertyp-Kennzeichnung enthält, erfordert die Elaboration der Untertyp-Festlegung, bevor die erzeugte Instanz zugeordnet wird. Als eine Folge der obigen Regeln ergibt sich, daß Deklarationen im Deklarationsteil eines Unterprogrammkörpers jedesmal elaboriert werden, wenn das entsprechende Unterprogramm aufgerufen wird. In einem solchen Fall kann die Elaboration einer Deklaration zu verschiedenen Ergebnissen mit unterschiedlichen Charakteristika führen. So kann zum Beispiel die Elaboration von ein und derselber Deklaration eines Untertyps in einem Unterprogrammkörper zu Untertypen mit unterschiedlichen Eigenschaften führen. FUNCTION diff_subtypes (N : INTEGER) RETURN INTEGER IS SUBTYPE my_int IS INTEGER RANGE 0 TO N; VARIABLE out_sig : my_int; BEGIN ... N ist hier als formaler Parameter eine Konstante (Default für formale Parameter vom Modus IN). Der actual Parameter, der mit N verknüpft wird, kann aber z.B. ein Signal sein => abhängig von N kann sich so der Untertyp my_int von Funktionsaufruf zu Funktionsaufruf ändern! ===== Elaboration einer Entwurfshierarchie ===== Durch die Elaboration einer Entwurfshierarchie werden eine Reihe von durch Netze verbundene Prozesse erzeugt, die anschließend zur Verhaltens-Simulation des zugrundeliegenden Entwurfs (Modell) ausgeführt werden können. Eine durch eine Entity definierte Entwurfshierarchie wird durch die Elaboration einer Blockanweisung umgesetzt, die dem durch die Entity definierten externen Block entspricht. Es besteht auch die Möglichkeit, die Entwurfshierarchie durch eine Konfiguration festzulegen. Dabei erfolgt eine Elaboration der Blockanweisung, die dem externen Block entspricht, der innerhalb der durch den entsprechenden Konfigurationsteil konfigurierten Entity definiert wird. Innerhalb einer Blockanweisung erfolgt die Elaboration jedes noch nicht ausgewerteten Packages und der wiederum darin enthaltenen Packages, wobei zunächst der Deklarationsteil der Package-Deklaration und, falls vorhanden, anschließend der Deklarationsteil des entsprechenden Package Bodys ausgeführt wird. {{:vhdl_reference_93:vhdlreference_elaborationdesignhierarchy.svg?nolink&500|Elaboration of a Design Hierarchy}} ===== Ausführung eines Modells ===== Ein erzeugtes //Modell// wird ausgeführt, indem die vom Anwender spezifizierten //Prozesse// elaboriert werden. Der Kernprozess stellt in der Entwurfshierarchie den Vorgang dar, welcher * die Aktivitäten der vom Anwender bereitgestellten Prozesse während der Simulation überwacht und koordiniert, * die Übertragung von Signalwerten sowie die Aktualisierung der Werte implizit definierter Signale (z.B. [[.:Predefined attributes#S'Stable(t)]]) bewirkt, * Ereignisse registriert und als Antwort darauf die Ausführung geeigneter Prozesse veranlaßt, eine Variable für jedes explizit im Modell deklariertes Signal mit dem gegenwärtigen Wert dieses Signals belegt und bei allen Berechnungen mit dem Signal den Wert der Variable bereitstellt, * die o.g. Variablenwerte während des Simulationsablaufs in regelmäßen Zeitabständen aktualisiert, * eine Variable für jedes implizit deklariertes guarded signal mit dem gegenwärtigen Wert dieses Signals belegt und je einen Treiber sowie eine den jeweils tatsächlichen Wert enthaltende Variable für * [[.:Predefined attributes#S'Stable(t)]]-Signale, * [[.:Predefined attributes#S'Quiet(t)]]-Signale, * [[.:Predefined attributes#S'Transaction]]-Signale und * im Modell verwendete Präfixe S und Zeiten t zur Verfügung stellt. ==== Die Ausbreitung von Signalwerten ==== Mit fortschreitender Simulationszeit erhalten die Signalverläufe in der Waveform die Werte der entsprechenden Treiber. Ein Treiber ist //aktiv// , wenn ihm ein neuer Wert zugewiesen wird. Ein Signal ist gerade //aktiv// , falls * eine der Signalquellen aktiv ist, * eines der Unterelemente aktiviert ist, * das Signal im formalen Teil eines Elements einer Port-Verknüpfungsliste verwendet wird und der tatsächliche Teil gerade aktiv ist oder * das Signal ein Unterelement eines aktiven resolved Signals ist. Hat ein Signal eines zusammengesetzten Typs eine auf anderen Typen basierende Quelle, so gilt jedes skalare Unterelement als aktiv, falls die Signalquelle aktiviert wird. Entsprechendes gilt für Ports und mit diesen verbundene Signale. Ein implizit definiertes Signal ist aktiv, wenn dieses Signal vom Kernprozess aktualisiert wird. Ist ein Signal nicht aktiv, so sagt man, daß das Signal //quiet// ist. Für bestimmte Signale verwaltet der //Kernprozess// zwei unterschiedliche Signalwerte. Der //Treiberwert// ist der Wert eines Signals, das anderen Signalen als Quelle dient. Der Effektivwert stellt den aus der Berechnung eines Signalbezuges innerhalb eines Ausdrucks erhaltenen Wert dar. Treiberwert und Effektivwert sind insbesondere dann nicht identisch, wenn eine [[.:Resolution function|Auflösungsfunktion]] oder Typumwandlungen involviert sind. Die Besonderheiten beider Signalarten zeigt die folgende Tabelle. ^ Signalart ^ Treiberwert ^ Effektivwert ^ | [[.:Scalar types|Skalares Signal]] S | S quellenlos: Treiberwert = Defaultwert | S deklariert per Signaldeklaration, Port vom Typ //buffer// oder unverbundener Port vom Typ //inout// : Effektivwert=Treiberwert | | ::: | Quelle von S ist Treiber, S nicht resolved: Treiberwert = Wert des Treibers | S ist verbundener Port vom Typ //in// oder //inout// : Effektivwert von S = Effektivwert des aktuellen Teiles des Zuordnungselements, Berechnung des Ist-Teiles | | ::: | Quelle von S ist Port, S nicht resolved: Treiberwert = Treiberwert des formalen Teils des Verbindungselements, das S mit dem Port verbindet | S sei unverbundener Port vom Typ //in// : Effektivwert = Defaultwert | | ::: | S ist resolved: Treiberwert = resolved Wert von S, Berechnen der "[[.:Resolution function|Auflösungsfunktion]]" mit den Treiberwerten der Quellen von S als Übergabeparameter | **Steuer- und Effektivwert haben den Untertyp von S** | | [[.:Compound types|Verbundsignal]] V zusammengesetztes Signal | Treiberwert = Zusammenfassung der Treiberwerte jedes skalaren Unterelements von V | Effektivwert = Zusammenfassung der Effektivwerte jedes skalaren Unterelements von V | Bei der Aktualisierung eines Signals berechnet der Kernprozess zunächst den Treiber- und Effektivwert. Dann wird die dem Signal zugehörige Variable neu belegt. Ist das Signal nicht von einem //Array-Typ// abgeleitet, so wird der Effektivwert verwendet. Es wird geprüft, ob dieser Wert zum Untertyp des Signals gehört. Die den gegenwärtigen Signalwert speichernde Variable erhält durch Zuweisung den Effektivwert. Liegt dem Signal ein //Array-Typ// zugrunde, wird der Effektivwert implizit in den Untertyp des Signals umgewandelt (einschließlich Test auf Konsistenz zwischen den Signal-Elementen und den Elementen des Effektivwertes). Das Ergebnis der Typumwandlung wird der o.g. Variablen zugewiesen. === Anmerkung === Ein Element eines Verbundsignals kann //quiet// sein, während das Signal selbst //aktiv// ist. Für Ports vom Typ //out// ist kein Effektivwert spezifiziert, da diese nicht gelesen werden dürfen. Obige Regeln gelten nicht für implizit definierte Signale. ==== Das Aktualisieren implizit definierter Signale ==== Vom Kernprozess werden die Werte implizit definierter //guarded signals// mit einer Blockanweisung, die einen guarded Ausdruck enthält, verbunden. Gleichzeitig aktualisiert das System die impliziten Signale [[.:Predefined attributes#S'Stable(t)]], [[.:Predefined attributes#S'Quiet(t)]] und [[.:Predefined attributes#S'Transaction]] sowie deren Treiber. Ein guarded Signal wird hinsichtlich seiner Momentanwerte nur verändert, falls der zugehörige guarded Ausdruck einen Bezug zum Signal herstellt und dieses Signal aktiv ist. Dabei wird der Wert des Ausdrucks berechnet und der Variablen zugewiesen, die den Momentanwert des Signals enthält. Für die Signale S'Stable(t), S'Quiet(t) sowie S'Transaction gibt es folgende Besonderheiten. ^ Merkmal ^ S'Stable(t) ^ S'Quiet(t) ^ S'Transaction ^ | Momentanwertänderung nur bei | Eintritt eines Ereignisses im momentanen Simulationszyklus | Aktivieren des Signals | Aktivieren des Signals | | ::: | Aktivieren des Treibers | Aktivieren des Treibers | | | Aktualisieren durch | Zuweisen des Wertes ' **false** ' an die zugehörige Variable, Treiber erhält die Form ' **true** ' nach der Zeit t | Zuweisen des Wertes ' **false** ' an die zugehörige Variable, Treiber erhält die Form ' **true** ' nach der Zeit t | Zuweisen des Ausdruck-Wertes an die zugehörige Variable (maximal **eine** Zuweisung inner-halb eines Simulationszyklus möglich) | | ::: | Zuweisen des Momentanwertes des Treibers an die zugehörige Variable | Zuweisen des Momentanwertes des Treibers an die zugehörige Variable | | Der Augenblickswert eines impliziten Signals D ist //abhängig// vom Momentanwert eines anderen Signals E, falls * D ein //guarded signal// darstellt und E innerhalb der //guarded expression// , die den Augenblickswert von D festlegt, auftaucht, * D vom Typ S'Stable(t), S'Quiet(t) oder S'Transaction ist. Innerhalb eines Simulationszyklus wird der Momentanwert von E **zeitlich vor** dem Augenblickswert von D aktualisiert, sodaß stets das Kausalitätsprinzip gilt. ==== Der Simulationszyklus ==== Die Ausführung eines Modells erfolgt durch die wiederholte Ausführung von Prozess-Anweisungen aus der Modellbeschreibungsebene. Eine Wiederholung bezeichnet man als Simulationszyklus. Innerhalb eines Zyklus werden alle Signalwerte berechnet. Davon abhängig startet das System die Ausführung von Prozess-Anweisungen, d.h. wenn an einem Signal ein Event auftritt werden alle Prozesse gestartet, die auf dieses Signal sensitiv sind. Der Ausführung geht eine aus den folgenden Schritten bestehende Initialisierung voran: * Die Treiber-und Effektivwerte aller //explizit deklarierten// Signale werden berechnet. Die Momentanwerte erhalten den effektiven Wert und gelten bis zum Zeitpunkt des Simulationsbeginns. * Der Wert //implizit deklarierter// Signale der Form [[.:Predefined attributes#S'Stable(t)]] oder [[.:Predefined attributes#S'Quiet(t)]] wird mit 'true' festgelegt. Signale des Typs [[.:Predefined attributes#S'Transaction]] bleiben undefiniert. * Das System belegt den Wert impliziter //guarded signals// mit dem Wert der entsprechenden //guarded expression// . * Jeder nonpostponed process des Modells wird einzeln ausgeführt (bis zur Unterbrechung). * Jeder postponed process des Modells wird bis zur Unterbrechung ausgeführt. * Die Zeit für den nächsten Simulationszyklus wird entsprechend 6. unten errechnet. Dem Simulationsbeginn ordnet man gewöhnlicherweise die Zeit 0 ns zu. Der Simulationszyklus besteht aus folgenden Teilen: * Sind alle Treiber inaktiv, wird die Simulationszeit auf den Zeitpunkt gesetzt, zu dem ein Treiber aktiv wird oder die Ausführung eines unterbrochenen Prozesses wieder aufgenommmen wird. Die Simulation ist beendet, wenn die Simulationszeit den Maximalwert erreicht hat. * Jedes aktivierte, //explizit deklarierte// Signal wird aktualisiert. Es können dabei sog. //Ereignisse// auftreten, auf deren Grundlage das System später entscheidet, welche Prozess-Anweisungen ausgeführt werden. * Alle //implizit deklarierten// Signale werden aktualisiert. * Jeder Prozess, der ein bestimmtes Signal in Verbindung mit einem Ereignis momentan beeinflußt, wird in der Ausführung fortgesetzt. * Alle bereits wiederaufgenommen nonpostponed process werden fortgesetzt und ausgeführt, bis eine Unterbrechung auftritt. * Die Zeit für den nächsten Simulationszyklus wird festgesetzt als früheste von folgenden Zeiten: * TIME'HIGH * Nächste Zeit zu der ein Treiber aktiv wird * Nächste Zeit zu der eine Prozeßabarbeitung wieder aufgenommen wird * Ist diese Zeit gleich der aktuellen Simulationszeit, wird ein neuer Delta Zyklus begonnen. * Soll kein neuer Delta Zyklus mehr begonnen werden, werden alle noch nicht ausgeführten postponed process abgearbeitet. Nun darf kein weiterer Delta Zyklus begonnen werden. Die Zeit für den nächsten Simulationszyklus wird nach 6. neu berechnet. ====== Lexikalische Elemente ====== ===== Buchstabenmenge ===== ==== Spezifikation ==== (g) Formatierungsanweisungen ( format_effectors ) sind * Tabulator (horizontal und vertikal), * Wagenrücklauf (carriage return), * Zeilenvorschub (line feed) und * Seitenvorschub (form feed). ===== Trenn- und Begrenzungszeichen ===== ==== Anmerkungen ==== Jedes lexikalische Element muß in eine Zeile passen, da das Zeilenende ein Trennzeichen bildet. ===== Bezeichner ===== ==== Anmerkungen ==== Ein Basis-Bezeichner darf keine Leerzeichen enthalten ! ===== Abstrakte Buchstabensymbole ===== ==== Anmerkungen ==== * Der Exponent darf für //integer_literals// nicht negativ sein. * Führende Nullen sind erlaubt. * Space ist nicht erlaubt, weil space ein Trennzeichen ist. * _ dient nur der Lesbarkeit und hat keinen Einfluß auf den Wert. * zulässige Basisangaben: 2,..,16 ==== Beispiele ==== Integer-Zahlen 12 0 1E6 123_456 Real-Zahlen 12.0 0.0 0.4556 3.14159_26 Real-Zahlen mit Exponent 1.34E-12 1.0E+6 6.023E+24 Integer-Zahlen vom Wert 255 2#1111_1111# 16#FF# 016#0FF# Integer-Zahlen vom Wert 224 16#E#E1 2#1110_0000# Real-Zahlen vom Wert 4095.0 (32 bit IEEE-Gleitkommaformat) 16#F.FF#E+2 2#1.1111_1111_111#E11 ===== Buchstaben ===== ===== Zeichenketten ===== ==== Anmerkungen ==== * Eine Zeichenkette darf nicht auf nachfolgende Zeilen übergreifen, da sie ein lexikalisches Element darstellt. * Zeichenketten, die nicht in eine Zeile passen, können in zwei oder mehrere Zeichenketten aufgeteilt und miteinander verkettet bzw. verbunden werden (s. Beispiel). * '"' innerhalb einer Zeichenkette muß als '""' eingegeben werden. ==== Beispiele ==== eine Fehlermeldung "setup time too small" eine leere Zeichenkette "" drei Zeichenketten der Länge 1 " " "a" """" "Zeichen wie $, % und } dürfen in Zeichenketten enthalten sein" "erster Teil einer Zeichenkette," & "die erst auf der nächsten Zeile endet"" ===== Bit-Zeichenketten ===== ==== Anmerkungen ==== Bei den Basisangaben steht B für binär, O für oktal und X für hexadezimal. ===== Kommentare ===== ==== Definition ==== Kommentare werden zur Erklärung des VHDL-Codes verwendet. ==== Beispiele ==== -- letzter Satz vor Wiedergabe des ALGOL 68-Berichts END ; -- Bearbeitung der Zeile beendet -- ein umfangreicher Kommentar kann in zwei oder mehrere -- aufeinanderfolgende Zeilen aufgeteilt werden ------- die ersten zwei Anstriche leiten den Kommentar ein ===== Reservierte Wörter ===== ==== Anmerkungen ==== Ein reserviertes Wort darf nicht als ein explizit deklarierter Bezeichner verwendet werden. ===== Ersetzen von Zeichen ===== ==== Definition ==== Ein vertikaler Strich (|) kann durch ein Ausrufezeichen (!), das für ein Operationszeichen ( //delimiter// ) steht, ersetzt werden. Die Doppelkreuze (#) in //based literals// können durch Doppelpunkte (:) ersetzt werden, vorausgesetzt die Ersetzung erfolgt bei beiden Zeichen. Die Anführungsstriche (") am Anfang und Ende von Zeichenketten können durch Prozentzeichen (%) ersetzt werden. Dabei müssen sowohl die Anführungsstriche am Anfang, wie auch die am Ende der Zeichenkette ersetzt werden. Dann dürfen aber innerhalb der Zeichenkette keine Anführungsstriche enthalten sein. Jedes in der Zeichenkette enthaltene Prozentzeichen muß dann verdoppelt werden. Dieses doppelte Prozentzeichen wird als ein einfaches Zeichen interpretiert. Der gleiche Austausch ist für //bit string literals// gestattet,vorausgesetzt es werden beide umschließende Anführungsstriche ersetzt. ====== Vordefinierte Attribute ====== ===== T'BASE ===== ^ Art | type | ^ Prefix | beliebiger Typ oder Untertyp T | ^ Ergebnistyp | Basistyp von T | ^ Beschränkungen | Dieses Attribut ist nur als Präfix zu Namen anderer Attribute zu verwenden, z. B. T'BASE'LEFT. | ===== T'LEFT ===== ^ Art | value | ^ Prefix | beliebiger skalarer Typ oder Untertyp T | ^ Ergebnistyp | gleicher Typ wie T | ^ Ergebnis | linker Wert von T | ===== T'RIGHT ===== ^ Art | value | ^ Prefix | beliebiger skalarer Typ oder Untertyp T | ^ Ergebnistyp | gleicher Typ wie T | ^ Ergebnis | rechter Wert von T | ===== T'HIGH ===== ^ Art | value | ^ Prefix | beliebiger skalarer Typ oder Untertyp T | ^ Ergebnistyp | gleicher Typ wie T | ^ Ergebnis | obere Grenze von T | ===== T'LOW ===== ^ Art | value | ^ Prefix | beliebiger skalarer Typ oder Untertyp T | ^ Ergebnistyp | gleicher Typ wie T | ^ Ergebnis | unterer Grenze von T | ===== T'ASCENDING ===== ^ Art | value | ^ Prefix | beliebiger skalarer Typ oder Untertyp T | ^ Ergebnistyp | boolean | ^ Ergebnis | TRUE wenn T einen steigenden Indexbereich hat, ansonsten FALSE. | ===== T'IMAGE(X) ===== ^ Art | function | ^ Prefix | beliebiger skalarer Typ oder Untertyp T | ^ Parameter | ein Ausdruck, der den Typ der Basistyp von T ist | ^ Ergebnistyp | string | ^ Ergebnis | Der Wert von X wird als string ausgegeben. Im Zweifelsfall in kleinen Buchstaben und ohne zusätzliche Zeichen (Ausnahmen: Extended Identifier -> \ ; Character Litera -> `). Physikalische Typen werden allgemein mit der Basiseinheit ausgegeben, außer der Typ TIME. Bei diesem bestimmt die eingestellte Auflösungsgrenze des Simulators die Einheit. Reale Zahlen werden entsprechend der Einstellung auf R Kommastellen genau ausgegeben. Unnötige Nullen werden bei Zahlen weggelassen. Die Zeicheersetzungen aus [[.:Replacing characters|See Ersetzen von Zeichen]] sind nicht erlaubt. | ^ Beschränkungen | Der Parametertyp muß im Subtyp des Prefix enthalten sein. | ===== T'VALUE(X) ===== ^ Art | function | ^ Prefix | beliebiger skalarer Typ oder Untertyp T | ^ Parameter | ein Ausdruck vom Typ string | ^ Ergebnistyp | Basistyp von T | ^ Ergebnis | Der Wert von T dessen string-Darstellung X ist. Zusätzliche Leerzeichen vorne oder hinten sind erlaubt und werden ignoriert. Numerische Typen werden können als Zahlen mit einer erlaubten Basis dargestellt werden. Bei Physikalischen Typen kann eine beliebige gültige Einheit verwendet werden. Die Zeicheersetzungen aus [[.:Replacing characters|See Ersetzen von Zeichen]] sind erlaubt. | ^ Beschränkungen | Der Parameter muß eine gültige string-Darstellung eines Wertes vom Typ T sein. | ===== T'POS(x) ===== ^ Art | function | ^ Prefix | beliebiger diskreter oder physischer Typ oder Untertyp T | ^ Parameter | Ausdruck, dessen Typ Basistyp von T ist | ^ Ergebnistyp | universal_integer | ^ Ergebnis | Position des Parameterwertes | ===== T'VAL(x) ===== ^ Art | function | ^ Prefix | beliebiger diskreter oder physischer Typ oder Untertyp T | ^ Parameter | Ausdruck, dessen Typ integer ist | ^ Ergebnistyp | Basistyp von T | ^ Ergebnis | Wert des Elements, dessen Positionsnummer gleich X ist | ^ Beschränkungen | Es tritt ein Fehler auf, wenn das Ergebnis nicht im Bereich T'LOW **to** T'HIGH liegt. | ===== T'SUCC(x) ===== ^ Art | function | ^ Prefix | beliebiger diskreter oder physischer Typ oder Untertyp T | ^ Parameter | Ausdruck, dessen Typ Basistyp von T ist | ^ Ergebnistyp | Basistyp von T | ^ Ergebnis | Wert des Elements, dessen Positionsnummer gleich X+1 ist | ^ Beschränkungen | Es tritt ein Fehler auf, wenn X=T'HIGH gilt, oder wenn X nicht im Bereich T'LOW **to** T'HIGH liegt. | ===== T'PRED(x) ===== ^ Art | function | ^ Prefix | beliebiger diskreter oder physischer Typ oder Untertyp T | ^ Parameter | Ausdruck, dessen Typ Basistyp von T ist | ^ Ergebnistyp | Basistyp von T | ^ Ergebnis | Wert des Elements, dessen Positionsnummer gleich X-1 ist | ^ Beschränkungen | Es tritt ein Fehler auf, wenn X=T'LOW gilt, oder X nicht im Bereich T'LOW **to** T'HIGH liegt. | ===== T'LEFTOF(x) ===== ^ Art | function | ^ Prefix | beliebiger diskreter oder physischer Typ oder Untertyp T | ^ Parameter | Ausdruck, dessen Typ Basistyp von T ist | ^ Ergebnistyp | Basistyp von T | ^ Ergebnis | Wert des Elements, das sich links von dem mit X angesprochenen Element befindet | ^ Beschränkungen | Es tritt ein Fehler auf, wenn X=T'LEFT gilt, oder X nicht im Bereich T'LOW **to** T'HIGH liegt. | ===== T'RIGHTOF(x) ===== ^ Art | function | ^ Prefix | beliebiger diskreter oder physischer Typ oder Untertyp T | ^ Parameter | expression whose base type is of the type T | ^ Ergebnistyp | Basistyp von T | ^ Ergebnis | Wert des Elements, das sich rechts von dem mit X angesprochenen Element befindet. | ^ Beschränkungen | Es tritt ein Fehler auf, wenn X=T'RIGHT gilt, oder X nicht im Bereich T'LOW **to** T'HIGH liegt. | ===== A'LEFT[(n)] ===== ^ Art | function | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist ein alias von diesem oder ein bedingter Array-Untertyp | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet. | ^ Ergebnistyp | Typ des linken Grenzelements des n'ten Indexbereiches von A. | ^ Ergebnis | Linkes Grenzelement des n'ten Indexbereiches von A | ===== A'RIGHT[(n)] ===== ^ Art | function | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist ein alias von diesem oder ein bedingter Array-Untertyp | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet | ^ Ergebnistyp | Typ des rechten Grenzelements des n'ten Indexbereiches von A | ^ Ergebnis | Rechtes Grenzelement des n'ten Indexbereiches von A | ===== A'HIGH[(n)] ===== ^ Art | function | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist ein alias von diesem oder ein bedingter Array-Untertyp | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet | ^ Ergebnistyp | Typ des oberen Grenzelements des n'ten Indexbereiches von A | ^ Ergebnis | Oberes Grenzelement des n'ten Indexbereiches von A | ===== A'LOW[(n)] ===== ^ Art | function | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist ein alias von diesem oder ein bedingter Array-Untertyp | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet. | ^ Ergebnistyp | Typ des unteren Grenzelements des n'ten Indexbereiches von A | ^ Ergebnis | Unteres Grenzelement des n'ten Indexbereiches von A | ===== A'RANGE[(n)] ===== ^ Art | range | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist, ein alias von diesem oder ein bedingter Array-Untertyp | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet | ^ Ergebnistyp | Typ des n'ten Indexbereiches von A | ^ Ergebnis | Der Bereich A'RIGHT(n) **to** A'LEFT(n) für eine ansteigende oder A'RIGHT(n) **downto** A'LEFT(n) für eine abfallende Richtung des n'ten Indexbereiches von A. | ===== A'REVERSE_RANGE[(n)] ===== ^ Art | range | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist, ein alias von diesem oder ein bedingter Array-Untertyp | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet | ^ Ergebnistyp | Typ des n'ten Indexbereiches von A | ^ Ergebnis | Der Bereich A'RIGHT(n) **downto** A'LEFT(n) für eine ansteigende oder A'RIGHT(n) **to** A'LEFT(n) für eine abfallende Richtung des n'ten Indexbereiches von A. | ===== A'LENGTH[(n)] ===== ^ Art | value | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist ein alias von diesem oder ein bedingter Array-Untertyp | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet | ^ Ergebnistyp | universal_integer | ^ Ergebnis | Anzahl der Werte des n'ten Indexbereiches | ===== A'ASCENDING[(n)] ===== ^ Art | value | ^ Prefix | Beliebiger Prefix, der als Arrayobjekt geeignet ist, ein alias von diesem oder ein bedingter Array-Untertyp. | ^ Parameter | Lokal statischer Ausdruck vom typ universal_integer, dessen Wert nicht die Dimension von A überschreiten darf. Bei Fehlen des Parameters wird der Defaultwert 1 verwendet. | ^ Ergebnistyp | boolean | ^ Ergebnis | TRUE wenn der n'te Indexbereich von A steigend definiert ist, ansonsten FALSE. | ===== S'DELAYED[(t)] ===== ^ Art | signal | ^ Prefix | Beliebiges Signal | ^ Parameter | Statischer Ausdruck des Typs time, der einen Wert größer 0 liefert. Bei Fehlen von t wird der Defaultwert 0 verwendet. | ^ Ergebnistyp | Basistyp von S | ^ Ergebnis | Ein um t Zeiteineheiten verzögertes Signal, äquivalent zu S. | ===== S'STABLE[(t)] ===== ^ Art | signal | ^ Prefix | Beliebiges Signal | ^ Parameter | Statischer Ausdruck des Typs time, der einen Wert größer 0 liefert. Bei Fehlen von t wird der Defaultwert 0 verwendet. | ^ Ergebnistyp | boolean | ^ Ergebnis | Ein Signal, das den Wert TRUE besitzt, wenn für t Zeiteinheiten kein Event an S aufgetreten ist; ansonsten besitzt es den Wert FALSE. | ===== S'QUIET[(t)] ===== ^ Art | signal | ^ Prefix | Beliebiges Signal | ^ Parameter | Statischer Ausdruck des Typs time, der einen Wert größer 0 liefert. Bei Fehlen von t wird der Defaultwert 0 verwendet. | ^ Ergebnistyp | boolean | ^ Ergebnis | Ein Signal, das den Wert TRUE besitzt, wenn S für t Zeiteinheiten ruhig war; ansonsten besitzt es den Wert FALSE. | ===== S'TRANSACTION ===== ^ Art | signal | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | bit | ^ Ergebnis | Ein Signal, dessen Wert innerhalb jeden Simulationszykluses, in dem das Signal S aktiviert wird, invertiert wird. | ^ Beschränkungen | Eine Beschreibung darf nicht vom Anfangswert von S'TRANSACTION abhängen. | ===== S'EVENT ===== ^ Art | function | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | boolean | ^ Ergebnis | Ein Signal, das den Wert TRUE besitzt, wenn im aktuellen Simulationszyklus ein Event an S aufgetreten ist; ansonsten besitzt es den Wert FALSE. | ===== S'ACTIVE ===== ^ Art | function | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | boolean | ^ Ergebnis | Ein Signal, das den Wert TRUE besitzt, wenn S im aktuellen Simulationszyklus aktiv ist; ansonsten besitzt es den Wert FALSE. | ===== S'LAST_EVENT ===== ^ Art | function | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | time | ^ Ergebnis | Die Anzahl der Zeiteinheiten seit dem letzten Eintreten eines Events an S. | ===== S'LAST_ACTIVE ===== ^ Art | function | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | time | ^ Ergebnis | Die Anzahl der Zeiteinheiten seit dem letzten Zeitpunkt, an dem S aktiv war. | ===== S'LAST_VALUE ===== ^ Art | function | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | Basistyp von S | ^ Ergebnis | Der letzte Wert von S vor dem letzten Wechsel | ===== S'DRIVING ===== ^ Art | function | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | boolean | ^ Ergebnis | S = skalar: FALSE wenn der Wert des Treibers von S im betrachteten Prozeß von einer NULL Transaktion bestimmt wird (inaktiv); ansonsten TRUE (aktiv). \\ S = zusammengesetzt: TRUE wenn für jedes Element R von S gilt R'DRIVING=TRUE; ansonsten FALSE. \\ S = leerer Arrayausschnitt: S'DRIVING=TRUE. | ^ Beschränkungen | Dieses Attribut ist nur innerhalb eines Prozesses, einer nebenläufigen Anweisung, für die ein entsprechender Prozeß ezistiert, und in Unterprogrammen verfügbar. Ist S ein Schnittstellensignal, muß dieses den mode inout, out oder buffer haben. Taucht dieses Attribut in einem Unterprogramm auf, so muß S ein formaler Parameter des Unterprogramms oder eines seiner Eltern sein und ein deklariertes Objekt einer Prozeß Anweisung sein. Der formale Parameter des Unterprogramms muß den mode inout oder out besitzen. | ===== S'DRIVING_VALUE ===== ^ Art | function | ^ Prefix | Beliebiges Signal | ^ Ergebnistyp | Basistyp von S | ^ Ergebnis | S = skalar: Aktueller Wert des Treibers von S im betrachteten Prozeß. \\ S = zusammengesetzt: Entsprechendes Aggregat. \\ S = leerer Arrayausschnitt: leerer Arrayausschnitt. | ^ Beschränkungen | Dieses Attribut ist nur innerhalb eines Prozesses, einer nebenläufigen Anweisung, für die ein entsprechender Prozeß ezistiert, und in Unterprogrammen verfügbar. Ist S ein Schnittstellensignal, muß dieses den mode inout, out oder buffer haben. Taucht dieses Attribut in einem Unterprogramm auf, so muß S ein formaler Parameter des Unterprogramms oder eines seiner Eltern sein und ein deklariertes Objekt einer Prozeß Anweisung sein. Der formale Parameter des Unterprogramms muß den mode inout oder out besitzen. S'DRIVING muß TRUE sein zur Zeit, wenn S'DRIVING_VALUE berechnet werden soll. | ===== E'SIMPLE_NAME ===== ^ Art | value | ^ Prefix | Beliebiges benamtes Objekt (siehe [[.:Attribute specification|See Attribut Spezifikation]]) | ^ Ergebnistyp | string | ^ Ergebnis | Der einfache Name, Character Symbol oder Operator Symbol des benamten Objekts ohne zusätzliche Leerzeichen vorne oder hinten. (Ausnahmen: Charakter Symbole -> ` und erweiterte Bezeichner-> \). Außer bei erweiterten Bezeichnern werden kleine Buchstaben verwendet. | ===== E'INSTANCE_NAME ===== ^ Art | value | ^ Prefix | Beliebiges benamtes Objekt (siehe [[.:Attribute specification|See Attribut Spezifikation)]]), außer lokale Ports und Generics einer Komponentendeklaration | ^ Ergebnistyp | string | ^ Ergebnis | Der komplette hierarchische Pfad samt eingebundenen Entities beginnend von der aktuellen Ebene bis zu dem bezeichneten Objekt. | ===== E'PATH_NAME ===== ^ Art | value | ^ Prefix | Beliebiges benamtes Objekt (siehe [[.:Attribute specification|See Attribut Spezifikation)]]), außer lokale Ports und Generics einer Komponentendeklaration | ^ Ergebnistyp | string | ^ Ergebnis | Der komplette hierarchische Pfad ohne eingebundenen Entities beginnend auf der obersten Ebene bis zu dem bezeichneten Objekt. | ===== B'BEHAVIOUR (nur VHDL'87) ===== ^ Art | value | ^ Prefix | Beliebiger Block oder beliebige Architektur einer Entity | ^ Ergebnistyp | boolean | ^ Ergebnis | Ein Wert, der TRUE ist, wenn der Block bzw. die Architektur keine Komponenteninstatiierung enthält; asnonsten ist der Wert FALSE. | ===== B'STRUCTURE (nur VHDL'87) ===== ^ Art | value | ^ Prefix | Beliebiger Block oder beliebige Architektur einer Entity | ^ Ergebnistyp | boolean | ^ Ergebnis | Ein Wert, der TRUE ist, wenn der Block bzw. die Architektur weder eine passive Prozeßanweisung noch eine nebenläufige Anweisung mit einer entsprechenden Prozeßanweisung enthält; asnonsten ist der Wert FALSE. |