VHLD Very High Speed Integrated Circuit (VHSIC) Hardware Description Language (VHDL) Język VHDL jest jednym z nowszych języków opisu i projektowania układów cyfrowych. W lipcu 1983 roku firmy Intermetrics, IBM oraz Texas Instruments rozpoczęły pierwszy etap pracy nad nowym językiem opisu i projektowania układów VLSI. Rok później zaimplementowano dany język, dzięki czemu w grudniu 1985 otrzymano pierwszą wersję narzędzia napisanego w języku Ada dla komputerów klasy VA 11/780 i IBM 370. Projekt VHDL był częścią programu Departamentu Obrony USA o nazwie VHSIC, którego zadaniem było opracowanie metod projektowania oraz wykorzystanie najbardziej złożonych i bardzo szybkich układów scalonych.w roku 1987 VHDL stał się obowiązującym standardem w dziedzinie języków opisu i projektowania układów VLSI. Ulepszona wersja języka pojawiła się dopiero w 1993 roku i obecnie jest stosowana przez większość projektantów układów cyfrowych na świecie. W języku VHDL można reprezentować układy cyfrowe na poziomach: od bramkowego do systemowego. Oznacza to, że najmniejszym elementem naszego projektu jest bramka logiczna. Nie mamy więc dostępu do poziomu analogowego (topografii bramki logicznej). Właściwości Języka VHDL ( ma typowe cechy języka wysokiego poziomu): wspiera hierarchiczność projektowanego sprzętu, umożliwia opis projektu i jego sprawdzenie w całym procesie jego powstania, umożliwia tworzenie nowych wersji projektowych realizowanych w nowych technologiach na postawie rozwiązań projektowych przechowywanych w bibliotece projektów - jest zatem niezależny od konkretnej technologii, metody projektowania, narzędzi wspomagających projektowanie, umożliwia reprezentację dynamiki układu cyfrowego oraz współbieżnych operacji w sprzęcie - można stworzyć równoważne modele funkcjonalne, ułatwia dokumentowanie projektu, a najlepsze rozwiązania można gromadzić w bibliotekach projektów, ułatwia wymianę informacji między projektantami oraz całymi zespołami projektowymi, Podstawowym elementem w języku VHDL jest jednostka projektowa, którą można przedstawić w postaci bloku o kilku wejściach i kilku wyjściach. Blok ten realizuję pewną funkcję logiczną lub pewną sekwenkcję logiczną. Jednostka projektowa definiuje swoje wejścia i wyjścia poprzez deklarację portów w bloku programowym nazywanym ENTITY. A funkcję, którą jednostka ma realizować opisuje się w bloku programowym nazywanym ARCHITECTURE. Blok ten może wykorzystywać równania boolowskie do opisu działania układy oraz bardziej ogólny zapis opisujący działanie jak ma się układ zachowywać. Trzeba pamiętać,że projekt w VHDL-u dotyczy układów logicznych co oznacza, że każde równanie i każdy opis dotyczy współbieżnej struktury logicznej także nie ma znaczenia kolejność występowania równań czy opisów. W VHDL-u komentarze umieszczane są nie jak w języku C po dwuznaku //, ale po dwuznaku - - ( dwa minusy )
ENTITY może być wspolna dla wielu BLOKOW ARCHTEKTURY. Przykład dla komparatorwa dwóch liczb 4 bitowych entity COMP_EQ is port ( O1 : out std_logic; IN0 : in std_logic_vector (3 downto 0); I N1 : in std_logic_vector (3 downto 0)); end COMP_EQ; Typy portow : OUT- wyjściowy IN- wejściowy INOUT - dwukierunkowy BUFFER wyjściowy z możliwością odczytu Język VHDL jest silnie określony na typy portów, zmiennych, sygnałow i stałych. TYPY służą do wyrażania wartości obiektow. Co to oznacza? Możemy porownywać lub przypisywać zmienne i sygnały nawzajem tylko tego samego typu np. integer tylko z integer, bit tylko z bit. Typy danych: bit bit_vector Boolean std_logic std_logic_vector std_ulogic integer unsigned signed Enumeration character
Można definiować własne typy przykładem może być typ definiowany licznik type licznik is integer range 0 to 127; Identyfikatory czyli nazwy zmiennych, stałych, procesow oraz elementow wejść i wyjść mogą się składać z liter, cyfr i znaku _ Wielkość liter nie ma znaczenia Nazwa musi się rozpoczynać od litery Nazwa nie powinna być dłuższa niż 16 znakow Przykład: Magistrala_16bit: signed; definicja prawidłowa 16bit_magistrala: signed; definicja zła _magistrala16bit: signed; definicja zła Sygnały są funkcjami czasu i są stosowane do łączenia ze sobą różnych portów symboli ( to jak linia połączeń w schemacie) signal nazwa_sygnalu : nazwa_typu [ograniczenie][:= wyrazenie]; Przykłady: signal zerowanie : bit := 1 ; -- inicjalizacja 1 signal wektor : bit_vector(0 to 3) := ( 0, 1, 1, 0 ); signal zmienna_8bitowa : integer range 0 to 255; -- ograniczenie od 0 do 255 Zmienne stosowane pomocniczo tylko w obrębie procesu lub podprogramu np. do indeksowania lub do łatwiejszego opisu działania układu variable nazwa_zmiennej : nazwa_typu [ograniczenie][:= wyrazenie]; variable uu : integer range 0 to 127 := 5; variable pp : integer range 500 downto 5 := 100; Stałe stosowane pomocniczo constant nazwa_stalej : typ := wyrazenie; Przykłady: constant vector : bit_vector(7 downto 0) := 11110010 ; Słowa kluczowe abs downto library postponed Srl access else linkage procedure Subtype after elsif literal process Then alias end loop pure To all entity map range Transport and exit mod record Type architecture file nand register Unaffected array for new reject Units assert function Next rem Until
attribute generate Nor report Use generic Not return Variable block group Null rol Wait body guarded Of ror When buffer if On select While bus impure Open severity With case in Or signal Xnor component inertial Others shared Xor configuration inout Out sla constant is Package sll disconnect label Port sra Typy boolean czy też bit lub bit_vector nie są często stosowane gdyż nie uwzględniają takich stanow jak wysoka impedancja czy też stan nieokreślony sygnału logicznego dlategonajczęściej stosuje się typy std_ulogic, std_logic, std_logic_vector zdefiniowane w bibliotece: IEEE.Std_Logic_1164.all library IEEE; use IEEE.Std_Logic_1164.all; Type std_logic is ( U, -- stan niezainicjowany X, -- wymusza stan nieznany 0, -- wymusza stan 0 1, -- wymusza stan 1 Z, -- stan wysokiej impedancji W, --słaby stan nieznany (odczyt) L, --słabe 0 (odczyt), rownoważne połączeniu przez rezystor z masą H, --słabe 1 (odczyt), rownoważne połączeniu przewodu przez rezystor z napięciem zasilania - -- stan nieokreślony, podobnie jak X ); 'U', 'W', '-' stany używane do procesow symulacyjnych
ATRYBUTY Dostarczają dodatkowych informacji o obiektach (np. sygnałach, zmiennych, typach lub komponentach) Składnia: obiekt atrybut[(parametr)]; Przykładowe atrybuty: EVENT rowny TRUE, gdy zachodzi zmiana wartości sygnału, STABLE rowny TRUE, gdy nie zachodzi zmiana wartości sygnału LEFT - zwraca lewą granicę zakresu RIGHT - zwraca prawą granicę zakresu RANGE - zwraca zakres typu type licznik is integer range 0 to 127; Przykłady: licznik left = 0 licznik right = 127 If Clock event and Clock = 1 then Q := D; Style opisu architektury 1.Styl behawioralny behavioral (opis działania) algorytmiczny opis sekwencji stanow, z użyciem procesu i instrukcji sekwencyjnych przepływowy - opis przepływu danych podczas przetwarzania, instrukcje wspołbieżne, rownania boolowskie; także opis układow sekwencyjnych z rejestrami styl RTL Register Transfer Logic 2.Styl strukturalny (opis budowy, czyli zapis połączeń komponentow ) Instrukcje wspołbieżne (Concurrent assignment statement) Przykład projektu wykorzystującego instrukcje wspołbieżne to znaczy takie, ktorych kolejność występowania w projekcie nie wpływa na działanie końcowe układu. (Operator przypisania do sygnału <=). library ieee; use ieee.std_logic_1164.all; entity and_or_4 is port ( A,B,C,D : in std_logic; Y0, Y1 : out std_logic); end and_or_4; architecture f1 of and_or_4 is y0 <= a and b and c and d; -- pamiętajmy VHDL nie rozrożnia wielkich Y1 <= A or B or C or D; -- i małych liter end f1;
Inne instrukcje wspołbieżne: with - select with wybor select sygnal <= wyrazenie1 when wartosc_wyboru1, sygnal <= wyrazenie2 when wartosc_wyboru2,..., sygnal <= wyrazenien when wartosc_wyborun, sygnal <= wyrazenie_koncowe when others; Przypisanie warunkowe when-else sygnal <= wyrazenie1 when warunek1a [and or warunek1b] else wyrazenie2 when warunek2a [and or warunek2b] else... wyrazenien when warunekna [and or waruneknb] else wyrazenie_koncowe; Przykład instrukcji wspołbieżnej with select dekoder 7-segmentowy library ieee ; use ieee.std_logic_1164.all; entity wyswietlacz is port ( count_in: in std_logic_vector (4 downto 0); LED: out std_logic_vector (6 downto 0)); end ; Architecture zachowanie of wyswietlacz is with count_in Select LED<= "1111001" when "0001", --1 "0100100" when "0010", --2 "0110000" when "0011", --3 "0011001" when "0100", --4 "0010010" when "0101", --5 "0000010" when "0110", --6 "1111000" when "0111", --7 "0000000" when "1000", --8 "0010000" when "1001", --9 "0001000" when "1010", --A "0000011" when "1011", --B "1000110" when "1100", --C "0100001" when "1101", --d "0000110" when "1110", --E "0001110" when "1111", --F "1000000" when others; --0 end zachowanie
Przykład instrukcji wspołbieżnych with select oraz when- else multiplekser entity multiplekser is -- jednostka o nazwie 'multiplekser' port( i0,i1,i2,i3 : in bit; -- deklaracja wejść s1,s0 : in bit; -- deklaracja wejść sterujących Y :out bit); -- deklaracja wyjścia end multiplekser; architecture cialo of multiplekser is -- architektura o nazwie 'opis' opisująca jednostką multiplekser signal wybor : integer range 0 to 3; -- deklaracja sygnału pomocniczego o nazwie 'wybor' -- 'wybor' jest liczba całkowita z zakresu od 0 do 3 with wybor select Y <= i0 when 0, i1 when 1, i2 when 2, i3 when others; end cialo; wybor <= 0 when s1='0' and s0='0' else 1 when s1='0' and s0='1' else 2 when s1='1' and s0='0' else 3; Przykład realizacji 8-bitowego rejestru dwukierunkowegoinstrukcje wspołbieżne when- else library ieee; use ieee.std_logic_1164.all; entity dataexch is port ( busadata : INOUT std_logic_vector (7 downto 0); busbdata : INOUT std_logic_vector (7 downto 0); buscdata : INOUT std_logic_vector (7 downto 0); busddata : INOUT std_logic_vector (7 downto 0); oe0, oe1 : IN std_logic) end dataexch; architecture behave of dataexch is busadata <= busbdata when oe0 = '1' else "ZZZZZZZZ"; busbdata <= busadata when oe0 = '0' else "ZZZZZZZZ"; buscdata <= busddata when oe1 = '1' else "ZZZZZZZZ"; busddata <= buscdata when oe1 = '0' else "ZZZZZZZZ"; end behave; Instrukcja procesu process - stosowana jako instrukcja wspołbieżna zawiera w sobie instrukcje sekwencyjne to znaczy takie, ktorych kolejność występowania ma wpływ na realizacje układu. Niekiedy process wykorzystuje się również gdy kolejność występowania nie ma wpływu na działanie układu, ale ułatwia to opis układu.
[etykieta_procesu:] process [(lista_wrazliwosci)][is][czesc_deklaracyjna] {instrukcje_sekwencyjne;} end process [etykieta_procesu]; Lista wrażliwości zawiera etykiety sygnałow, ktore powodują wykonanie instrukcji sekwencyjnych wewnątrz procesu, gdy tylko ktorykolwiek z nich zmieni wartość. Lista ta jest opcjonalna, lecz gdy jej nie ma, to musi być wprowadzona wewnątrz procesu sekwencyjna instrukcja czekania wait. Etykieta procesu służy tylko do polepszenia czytelności zapisu. W części deklaracyjnej mogą być umieszczone deklaracje typow (type), stałych (constant) i zmiennych lokalnych (variable). Procesy nie mogą być zagnieżdżane. INSTRUKCJE SEKWENCYJNE Służą do opisu procesow oraz podprogramow (procedury, funkcje) : Przypisanie <= Wywołanie procesu przypisanie do zmiennej (:=) instrukcja warunkowa if-then-else instrukcja wyboru case instrukcja czekania wait instrukcja pętli loop i związane instrukcje exit i next instrukcja pusta null instrukcja testowa assert If-then-else Sekwencyjny odpowiednik wspołbieżnej instrukcji przypisania warunkowego when-else, ktorej nie można stosować w obrębie procesu ani podprogramu. Składnia: if warunek1 then {instrukcja sekwencyjna1;} elsif warunek2 then {instrukcja sekwencyjna2;} elsif warunek3 then {instrukcja sekwencyjna2;}... else {instrukcja sekwencyjnan;} end if; Wynik warunku jest typu boolean (false lub true). Gdy warunek jest spełniony (true), to wykonywana jest sekwencja instrukcji następująca bezpośrednio po słowie then. W przeciwnym razie (else) wykonywana jest inna sekwencja albo sprawdzany jest kolejny warunek (elsif warunek then) i tak dalej. Sprawdzanie warunkow następuje kolejno, a więc kolejność warunkow określa odpowiednio priorytet. Przykład komparatora dwóch liczb 4 bitowych entity COMP is end COMP; port (O1 : out std_logic; O2 : out std_logic; IN0 : in std_logic_vector (3 downto 0); IN1 : in std_logic_vector (3 downto 0));
architecture IMP_COMP of COMP is F_COM : process (IN0,IN1) -- process FUNCTION_GT if IN0 > IN1 then O1 <= '1'; O2 <= '0': elsif IN0 < IN1 then O1 <= '0'; O2 <= '1': else O1 <= '0'; O2 <= '0': end if; end process F_COM; end IMP_COMP; case Odpowiednik wspołbieżnej instrukcji przypisania selektywnego with-select-when. Składnia: case wyrazenie is when wybor1 => {instrukcja sekwencyjna1;} when wybor2 => {instrukcja sekwencyjna2;}... when wyborn => {instrukcja sekwencyjnan;} when others => {instrukcja sekwencyjnak;} end case; Wybor jest pojedynczą wartością wyrażenia albo grupą takich wartości. Przy opisie należy wymienić wszystkie wzajemnie wyłączające się wartości, albo dla wartości nieużywanych wprowadzić zapis when others => sekwencja_instrukcji; lub when others => null; -- brak działania Sprawdzanie wartości wyboru następuje rownolegle (jednocześnie), czyli żadna z nich nie ma priorytetu względem innych. Przykład multipleksera 2 wejsciowego (a,b) z sygnałem wyboru s library ieee ; use ieee.std_logic_1164.all; entity mux2x1vhd is port ( z: out std_logic; a, b, s: in std_logic ); end ;
architecture mux2x1_arch of mux2x1vhd is process (s, a, b) case s is when '0' => z <= a; when '1' => z <= b; when others => z <= 'X'; end case ; end process ; end mux2x1_arch; Przykład demultipleksera 8- wyjściowego z trzema sygnałami enable.e3 aktywny '1',a N_E2 i N_E1 aktywne '0' loop Pętla loop umożliwia zapis powtarzania sekwencji instrukcji. Wyrożniamy trzy rodzaje pętli: for, while i pętle nieskończone Jeśli liczba obiegow pętli jest z gory znana, stosujemy instrukcję for-loop [etykieta:] for parametr in zakres loop {instrukcja sekwencyjna;} end loop [etykieta]; parametr określa zakres i kierunek indeksowania (to lub downto). Przykład, XOR poszczegolnych bitow wektora A i C można opisać: for x in 0 to A length - 1 loop B(i) <= A(i) xor C(i); -- B zawiera xor-a bitow A i C end loop;
Indeks i nie musi być odrębnie deklarowany i jest rozpoznawany wyłącznie w obrębie tej instrukcji. Atrybut length umożliwia identyfikację długości wektora. Jeśli liczba iteracji zależy od wyniku sprawdzania warunku przed powtorzeniem pętli, to stosuje się instrukcję while-loop [etykieta:] while warunek loop {instrukcja sekwencyjna;} end loop [etykieta]; Instrukcja exit[etykieta_petli][when warunek]; służy do wyjścia z pętli, jeśli warunek jest spełniony. Można zrezygnować z opcji [when warunek], ale oznacza to bezwarunkowe wyjście z pętli przy pierwszym napotkaniu słowa exit podczas wykonywania instrukcji. Warunek można też wprowadzić stosując instrukcję warunkową if-then: if warunek then exit; end if; Instrukcja next [etykieta_petli][when warunek]; służy do zakończenia wykonywania bieżącej iteracji pętli i przejście do następnej, jeśli warunek jest spełniony. Jednocześnie indeks pętli zwiększa się o jeden.