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 technologi , 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 o
ł wa 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
begin
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.al
library IEEE;
use IEEE.Std_Logic_1164.al ;
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
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
begin
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;
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
begin
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
begin
with wybor select
Y <= i0 when 0,
i1 when 1,
i2 when 2,
i3 when others;
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;
end cialo;
Przykład realizacji 8-bitowego rejestru dwukierunkowego-
instrukcje 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
begin
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]
begin
{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
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)); end COMP;
architecture IMP_COMP of COMP is begin
F_COM : process (IN0,IN1)
begin -- 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
begin
process (s, a, b)
begin
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.