Język opisu sprzętu VHDL
Materiały pomocnicze dla przedmiotu
"Technika cyfrowa i mikroprocesorowa" II/III RA
Krzysztof Kołek
Katedra Automatyki, Akademia Górniczo-Hutnicza
Al. Mickiewicza 30, 30-059 Kraków
tel. (0-12) 617-28-55
kko@aquarium.ia.agh.edu.pl
Spis treści
1. Wstęp
Wstęp
Język VHDL (skrót pochodzi od dwóch innych skrótów: V - Very High Speed Integrated Circuit oraz HDL - Hardware Description Language) rozwijany był na początku lat 80-tych do opisu niezależnych metod opisywania układów elektronicznych przez American Department of Defence (ang. DoD). Po raz pierwszy został zestandaryzowany w roku 1983, a następnie standaryzację powtórzono w latach 1987 oraz 1993.
Główne cechy języka VHDL to:
równoległość przejawiająca się w możliwości zdefiniowania potrzeby oraz wykonywania równoległego (jednoczesnego w czasie) przetwarzania różnych porcji informacji,
strukturalność oznaczająca możliwość hierarchicznego opisywania projektów. W opisie hierarchicznym projekt zbudowany jest z połączonych bloków o mniejszym stopniu złożoności, które z kolei zbudowane są z prostszych bloków, które zawierają w sobie jeszcze prostsze bloki i tak dalej aż dochodzimy do bloków podstawowych, którymi np. w przypadku układów cyfrowych są bramki logiczne. Strukturalność oznacza możliwość opisu sprzętu od poziomu systemu do poziomu bramki,
"redesign" - typowy projekt cyfrowego układu elektronicznego zawiera w sobie do 80% fragmentów z innych projektów. Nowe projekty nie powstają w pustce. Projektanci wykorzystują poprzednio zdobyte doświadczenia przenosząc opracowane i poznane uprzednio rozwiązania do nowych projektów. Proces ten określa się pochodzącym z języka angielskiego słowem redesign,
możliwość wykonywania instrukcji sekwencyjnie (czyli w sposób przeciwstawny do wykonywania równoległego) oznaczająca możliwość definiowania czynności wykonywanych jedna po drugiej, w sposób analogiczny jak w tradycyjnych językach programowania. ,
zdolność do jednolitego opisywania struktury układów zbudowanych w oparciu o różne technologie stwarzająca możliwość przenoszenia projektów pomiędzy różnymi platformami sprzętowymi,
możliwość symulowania projektowanych układów; możliwość tworzenia sekwencji sygnałów testujących. Istnieje możliwość wbudowania sygnałów testowych w projekt,
"samodokumentowanie" osiągnięte dzięki prostej i przejrzystej strukturze,
modelowanie układów z uwzględnieniem upływającego czasu.
Programowanie w języku VHDL może odbywać się na różnych poziomach abstrakcji. Są to:
warstwa topograficzna (ang. layout) specyfikująca połączenia z uwzględnieniem również zależności czasowych i efektów analogowych. Przykładowo realizuje opóźnienia propagacji sygnału oraz blokowanie sygnałów poniżej minimalnej zadanej szerokości,
warstwa logiki zawierająca informację o funkcjach, architekturze, technologii i szczegóły zależności czasowych. Podstawowo opisuje zależności logiczne między blokami,
warstwa RTL (ang. Register Transfer Level) - zawiera opis każdego rejestru oraz logiki między nimi. Zawiera informacje o architekturze ale nie o technologii. Zależności czasowe nie są specyfikowane. Istotna jest tylko informacja o zegarach taktujących,
warstwa behawioralna (ang. behavioural) opisująca funkcje projektu. Zawiera tak dużo informacji o zależnościach czasowych, jak jest to niezbędne do opisaniu funkcji projektu.
Każdy element opisywany w języku VHDL może posiadać dowolną liczbę definicji w każdej z omówionych warstw. Umożliwia to skupienie się w różnych fazach projektu na różnych jego aspektach.
Język przypomina języki programowania typu C lub Pascal jednak jego podstawowym celem nie jest wykonywanie obliczeń. Zadaniem języka jest wspieranie całości procesu projektowania układów cyfrowych poczynając od symulacji poprzez modelowanie, testowanie, implementacje oraz tworzenie dokumentacji. Podstawowym celem języka VHDL jest "zaprogramowanie" programowalnego układu logicznego niezależnie od technologii w jakiej ten układ został wytworzony (ASIC, FPGA, PLD, itp.). Dotyczy to również układów opracowywanych w przyszłości, których parametry nie są jeszcze aktualnie znane.
Podstawowym ograniczeniem języka VHDL jest, iż pierwotnie był projektowany wyłącznie do systemów cyfrowych. Aktualnie trwają prace nad standaryzacją wersji dla układów analogowych oraz nad opracowaniem analogowych programowalnych i konfigurowalnych układów scalonych o podobnym stopniu elastyczności jaki osiągnęły układy FPGA w technice cyfrowej.
Dostępne oprogramowanie wspomagające użytkowanie języka zwykle automatycznie tworzy i optymalizuje struktura komórek i połączeń podczas programowanie programowalnych układów logicznych. Język VHDL wydaje się być szczególnie użyteczny dla układów FPGA o 10-20 tysiącach komórek. Narzędzia języka HVDL dla układów FPGA kosztują od 1 do 20 tysięcy USD (w porównaniu z cenami 50-100 tysięcy USD dla układów ASIC).
Niniejsze opracowanie przedstawia skrótowy opis struktur języka VHDL ukierunkowany na wykorzystanie do programowania programowalnych układów logicznych firmy XILINX z wykorzystanie firmowego oprogramowania wspomagany przez pakiet oprogramowanie ORCAD w wersji 7.11. Należy zwrócić uwagę na występujące różnice między opisem standardu języka VHDL oraz jego implementacją w programie ORCAD. Praktyczna implementacja zawiera bowiem istotne ograniczenia w stosunku do ogólnej specyfikacji języka podyktowane kłopotami w realizacji niektórych cech w oparciu o aktualną technologię. Specyfikacja języka, będąc bardzo elastyczną, uwzględnia cechy, które aktualnie mogą być wyłącznie symulowane w sposób programowy (nie jest możliwa ich praktyczna realizacja z zastosowaniem okładów firmy XILINX) nie należy jednak wykluczyć ich praktycznej realizacji w oparciu o nowe rozwiązania technologiczne.
Podstawowe pojęcia języka VHDL
Poniżej przedstawiono podstawowe pojęcia występujące w opisie języka VHDL. Należy pamiętać, iż język VHDL został zaprojektowany jako język opisu sprzętu. Powoduje to istotne różnice w stosunku do języków programowania ogólnego przeznaczenia. Język VHDL wykazuje duże podobieństwa składniowe do języków typu Pascal lub C niemniej podobnie wyglądające instrukcje mogą charakteryzować się dramatycznie odmiennym zachowaniem. W szczególności dotyczy to zasad określania zależności czasowych oraz pracy równoległej.
Predefiniowane typy
Język VHDL posiada następujące predefiniowane typy danych:
BOOLEAN przyjmuje jedną z dwóch wartości: FALSE lub TRUE,
BIT jest równe '1' lub '0',
BIT_VECTOR ciąg wartości typu BIT np. "000000", "01101". Można użyć do modelowania magistral,
CHARACTER umożliwia używanie znaków alfanumerycznych np. 'a', 'X',
STRING definiuje ciągi znaków np. "ABCD", "012ws"
INTEGER reprezentuje liczby całkowite,
REAL umożliwia zapis liczb zmiennopozycyjnych.
Powyższe typy powinny być zdefiniowane w pakiecie STANDARD wchodzącym w skład języka. Definicja pewnych typów może być zależna od implementacji lub nie występować. Dotyczy to na przykład typu REAL, który ze względu na problemy implementacyjne nie zawsze jest dostępny.
Logika wielowartościowa
Logika wielowartościowa posiada więcej typów niż tylko zero i jedynka logiczna. Pakiet Std_Logic_1164 wchodzący w skład języka VHDL zawiera definicję typów std_logic (typ "resolved") oraz std_ulogic (typ "unresolved") o następujących wartościach wraz z operującymi na nich funkcjami:
'U' - wartość nigdy dotychczas nie została określona,
'X' - wartość była znana ale aktualnie nie można podać jej konkretnej wartości; sygnał "strong drive",
'0' - sygnał logicznego 0 typu "strong drive",
'1' - sygnał logicznej 1 typu "strong drive",
'Z' - stan wysokiej impedancji; sygnał nie posiada "driver"-a,
'W' - wartość była znana ale aktualnie nie można podać jej konkretnej wartości; sygnał "weak drive"; rzadko używany,
'L' - sygnał logicznego 0 typu "weak drive",
'H' - sygnał logicznej 1 typu "weak drive",
'-' - wartość sygnału nie ma znaczenia.
Pakiet zawiera również definicje typów Std_logic_vector oraz Std_ulogic_vector.
Pakiet Std_logic zawarty jest w bibliotece IEEE. Poniższe instrukcje czynią elementy zdefiniowane w pakiecie Std_logic dostępnymi w projekcie:
library IEEE; -- Uczyń bibliotekę dostępną
use IEEE.Std_Logic_1164.all; -- Całość biblioteki dostępna
Jest możliwe podstawianie elementów typu std_ulogic do std_logic i vice-versa.
Komponenty
Opis komponentów składowych projektu wykonywany jest za pomocą dyrektywy ENTITY opisującej sprzęg w strukturze hierarchicznej, bez definiowania zachowania. Jest odpowiednikiem symbolu na schemacie. Przykładowy opis komponenty przedstawiony jest poniżej.
ENTITY halfadd IS
PORT ( a,b : IN BIT;
sum, carry : OUT BIT);
END halfadd;
Blok ENTITY zawiera definicje sygnałów wejściowych i wyjściowych komponentu. Może również zawierać definicje parametrów i stałych. Opisany blok o nazwie halfadd posiada dwa wejścia (a oraz b) oraz dwa wyjścia (sum oraz carry). Wszystkie wejścia i wyjścia są typu BIT. Przedstawiony powyżej przykład odpowiada następującemu blokowi:
Zachowanie komponentu opisane jest w bloku ARCHITEKTURE.
ARCHITECTURE behave OF halfadd IS
BEGIN
sum <= a XOR b;
carry <= a AND b;
END behave;
Po słowie ARCHTECTURE znajduje się zdefiniowana przez użytkownika nazwa. Blok ARCHTECTURE jest zawsze związany z blokiem ENTITY. Znaki '<=' są symbolami przypisania nowych wartości do sygnałów. Każdy blok ENTITY może posiadać kilka, różniących się nazwami, bloków ARCHTECTURE. Umożliwia to opisanie projektu na różnych poziomach abstrakcji.
Pakiety
W języku VHDL można pogrupować komponenty oraz ich właściwości w postaci pakietów. Pakiet jest zbiorem definicji, które mogą być dostępne przez wiele projektów w tym samym czasie. Jest odrębną jednostką projektową w VHDL. Występuje na zewnątrz rozważanych dotychczas jednostek (ENTITY i ARCHITECTURE). Może zawierać definicje stałych, typy definiowane przez użytkownika, deklaracje komponentów oraz podprogramy VHDL, które są dzielone pomiędzy różne projekty.
Pakiety definiuje się za pomocą dyrektywy PACKAGE.
Przykładowym pakietem jest Std_Logic_1164 zawierający między innymi definicje podstawowych typów.
Podprogramy
Język VHDL umożliwia definicję zarówno funkcji jak i procedur, które ogólnie zwane są podprogramami. Przykładem działania funkcji jest transkodowanie, czyli zmiana zapisu liczby w jednym kodzie na inny (patrz przykład poniżej). Taka sama operacja może zostać zrealizowana za pomocą procedury (patrz drugi przykład). Różnica polega na zwracane wartości: procedura nie zwraca żadnej wartości i w związku z tym nie może zostać użyta np. w instrukcjach przypisania podczas gdy funkcja zwraca wartość określonego typu. Ewentualne wartości modyfikowane przez procedurę muszą zostać zadeklarowane na jej liście argumentów jako wyjściowe lub wejściowo/wyjściowe (out lub inout).
function Transcod(Value: in bit_vector(0 to 7)) return bit_vector is
begin
case Value is
when "00000000" => return "01010101";
when "01010101" => return "00000000";
when others => return "11111111";
end case;
end Transcod;
procedure Transcoder_1 (variable Value: inout bit_vector (0 to 7)) is
begin
case Value is
when "00000000" => Value:="01010101";
when "01010101" => Value:="00000000";
when others => Value:="11111111";
end case;
end procedure Transcoder_1;
Operatory
Operatory dostępne w języku VHDL przedstawia poniższa tabela. Przedstawione operatory działają na standardowych typach wbudowanych w język. Mogą zostać niezależnie zdefiniowane dla typów definiowanych przez użytkownika.
|
Operator |
Typy operandów |
Typ wyniku |
Logiczne |
AND, OR, NAND, NOR, XOR, XNOR, NOT |
BIT lub BOOLEAN (BIT_VECTOR, STD_LOGIC, STD_LOGIC_VECTOR, STD_ULOGIC, STD_ULOGIC_VECTOR) |
BIT lub BOOLEAN (BIT_VECTOR, STD_LOGIC, STD_LOGIC_VECTOR, STD_ULOGIC, STD_ULOGIC_VECTOR) |
Porównań |
=, /=, <, <=, >, >= |
Wszystkie typu |
BOOLEAN |
Przesunięć |
SLL, SRL, SLA, SRA, ROL, ROR |
Lewostronny: BIT lub wektor BOOLEAN; prawostronny: INTEGER |
BOOLEAN |
Dodawania |
+, -, & |
Tablica numeryczna lub element tablicy |
Tego samego typu jak operandy |
Znak |
+, - |
Numeryczny |
Tego samego typu jak operandy |
Mnożenia |
*, / |
INTEGER, REAL |
Tego samego typu jak operandy |
|
MOD, REM (reszta z dzielenia, różnie działają w zależności od znaku operandu) |
INTEGER |
Tego samego typu jak operandy |
Inne |
ABS |
Numeryczny |
Tego samego typu jak operandy |
|
** (potęgowanie) |
Lewostronny: numeryczny; prawostronny: INTEGER |
Tego samego typu jak lewostronny operand |
Spośród operatorów logicznych wszystkie oprócz NOT posiadają identyczny priorytet. Operator NOT posiada priorytet wyższy od pozostałych operatorów logicznych.
Dla argumentów typu tablicowego argumenty są wyrównywane w lewo i porównywane. Powoduje to, że '111' jest większe od '1011'. Oznacza to, że z wektorem nie jest związana żadna wartość numeryczne. To tylko zbiór elementów tego samego typu.
Podstawowo operatory arytmetyczne zdefiniowane są dla typów integer, real oraz time. Wykonywanie operacji arytmetycznych dla typów takich jak np. std_logic wymaga zdefiniowania funkcji definiujących operatory dla takich typów. Jest to możliwe ponieważ język VHDL umożliwia definiowanie znaczenia operatorów.
Dla operatorów arytmetycznych można wyspecyfikować zakres argumentów i wyniku:
entity ADD is
port(A, B : in integer range 0 to 7;
Z : out integer range 0 to 15);
end ADD;
architecture ARITHMETIC of ADD is
begin
Z <= A + B;
end ARITHMETIC;
Zmienne typu time można mnożyć i dzielić zarówno przez integer jak i real:
signal CLK : std_ulogic;
constant PERIOD : time := 50 ns;
wait for 5 * PERIOD;
wait for PERIOD * 1.5;
CLK <= not CLK after PERIOD/2;
Sygnały, zmienne, stałe
|
Właściwe rozumienie cech oraz zasad użycia sygnałów oraz zmiennych jest najbardziej istotną cechą języka VHDL. |
Sygnały w języku VHDL służą do reprezentacji rzeczywistych połączeń między elementami projektu. Odpowiadają więc połączeniom pojedynczym lub magistralom. Z sygnałami związane są opóźnienie w związku z propagacją sygnału oraz zdolność tłumienia sygnałów o czasie trwania krótszym od zadanego. Operatorem przypisania w stosunku do sygnałów jest '<='. Przykładowo instrukcja:
z <= a;
powoduje przypisanie do sygnały z wartości sygnału a.
Każdy sygnał ma z sobą związany wzmacniacz będący źródłem wartości sygnału. Przedstawione powyżej podstawienie odpowiada sytuacji:
Podstawienie wartości do sygnału oznacza w rzeczywistości ustawienie wartości wyjściowej ze wzmacniacza. Jeżeli występuje więcej niż jedno podstawienie do sygnału wówczas odpowiada to sytuacji gdy pojedynczy sygnał ma kilka związanych z nim wzmacniaczy. Pamiętając iż instrukcje mogą wykonywać się w sposób równoległy poniższy ciąg podstawień:
z <= a;
z <= b;
odpowiada sytuacji
Takie rozwiązanie jest zwykle niedopuszczalne. Wielokrotne podstawienie wartości do sygnału powoduje utworzenie wielu wzmacniaczy będących źródłem wartości sygnału. Jedynym przypadkiem dopuszczalności, a nawet dużej użyteczności takiego rozwiązania, jest zdefiniowanie sygnału z jako typu resolved. Oznacza to związanie z sygnałem z specjalnej funkcji, która określa jaka jest wartość sygnału w przypadku gdy jest on sterowany z dwóch wzmacniaczy.
W przypadku wielokrotnego podstawiania wartości do tego samego sygnału wykonywanego sekwencyjnie wykona się wyłącznie ostatnie podstawienie. Każde sekwencyjnie podstawienie wartości do sygnału "anuluje" poprzednie sekwencyjne podstawienia. Wszystkie takie podstawienia wpływają na wyjście tego samego wzmacniacza sygnału.
Podstawienia do sygnału w różnych sekwencyjnych fragmentach programu wykonywane jest równolegle i produkuje wielokrotne wzmacniacze dla podstawianego sygnału. W takim przypadku niezbędnym jest zdefiniowanie funkcji określającej wartość sygnału.
Przypisując wartość do sygnału można określić uzależnienia czasowe związane z taką operacją. Przypisania sygnałów mogą posiadać zdefiniowane opóźnienia typu inertial lub transport. Dodatkowo opóźnienie typu inertial może posiadac wyspecyfikowany parametr reject.
Podstawienie do zmiennej wykonywane jest za pomocą operatora <=. Instrukcja:
z <= a AFTER 5 NS;
powoduje przypisanie wartości sygnału a do sygnału z po 5 nanosekundach. Dodatkowo impulsy o długości poniżej 5 nanosekund pojawiające się w sygnale a nie powodują zmian wartości sygnału z.
Podstawienie
z <= REJECT 3 NS INERTIAL a AFTER 5 NS;
wprowadza opóźnienie 5 nanosekund i wycina impulsy o długości poniżej 3 nanosekund. Odpowiada to linii sygnałowej o zadanym opóźnieniu i ograniczonym paśmie.
Podstawienie
z <= TRANSPORT a AFTER 5 NS;
powoduje opóźnienie sygnału o 5 nanosekund. Dowolnie krótki impuls jest przenoszony. Odpowiada to linii o nieskończonym widmie i może np. posłużyć do modelowania linii opóźniających.
Podstawienie
z <= '1' AFTER 3 NS, '0' AFTER 7 NS, '1' AFTER 17 NS;
tworzy falę 1->0->1 zmieniającą wartości w chwilach czasu 3 ns, 7 ns oraz 17 ns.