JĘZYKI HDL - DMCS Pages for Students

Download Report

Transcript JĘZYKI HDL - DMCS Pages for Students

VHDL
K. Przygoda
Plan Szkolenia
•
•
•
•
•
•
•
•
•
•
Wstęp
Budowa i składnia
Układy kombinacyjne
Komponenty
Układy sekwencyjne
Przerzutnik
Licznik
Rejestr przesuwny
Automaty
Magistrale
JĘZYK VHDL
• Geneza: komputerowa symulacja układu cyfrowego, Departament
Obrony USA
• opis skomplikowanego systemu w postaci schematu jest
nieczytelny, szybkie wprowadzanie zmian w opisie układu
• języki HDL: VHDL, Verilog, Abel
• zalety: więcej informacji niż w opisie schematowym, krótszy cykl
projektowy złożonych układów, niezależność od technologii, opis
na różnych poziomach abstrakcji, symulacja na różnych etapach
zaawansowania projektu, standaryzacja
• wady: zmiana stylu projektowania, koszty narzędzi, szkoleń,
problem syntezowalności, jakość syntezy, trudność oceny
złożoności projektu
• VHDL- skrót: VHSIC (Very High Speed Integrated Circuit)
Hardware Description Language, standard IEEE1076 -1987,
IEEE1164-1993r
Poziomy abstrakcji (style opisu układów):
• behawioralny (algorytmiczny,
systemowy) -opis działania układu bez
szczegółów realizacyjnych (procesy,
pętle)
• RTL (przesłań międzyrejestrowych,
Dataflow)
• logiczny (wyrażeń boolowskich,
bramek)
• strukturalny (podział na podukłady,
wielokrotne wykorzystanie
podukładów)
•zasady opisu strukturalnego:
•pełny układ można rozłożyć na komponenty,
•stopień złożoności komponentów jest dowolny
•brak ograniczeń co do liczby poziomów hierarchii
•najniższy poziom hierarchii musi mieć zdefiniowany model
działania (styl behawioralny, RTL lub logiczny)
•elementy modelu działania:
•sygnały (odpowiedniki fizycznego połączenia, fizycznych
wartości logicznych w układzie)
•procesy (operacje na wartościach logicznych w układzie)
•współbieżne wykonywanie operacji
poszczególne części układu
działają w sposób równoległy
•dwa rodzaje kodu VHDL:
•kod współbieżny
•kod sekwencyjny (procesy)
Elementy składni języka
* Przypisanie wartości sygnału:
sample <= “0000”
next_sample <= sample
* Operatory relacyjne: =, /=, >, <, <=, >=
* Operatory logiczne: and, xor, or, nand, nor, xnor, not
* Operatory arytmetyczne: +, -,
*, /, mod, rem
* Operatory znaku: +, * Operator sklejania: &
*Wyrażenie “if -then -elsif -end if” (tylko procesy)
*Wyrażenie “case -when..-when.. -end case” (tylko procesy)
*Wyrażenie “for” (pętle w procesach, generacje)
*Wyrażenia “when - else” oraz “with.. select” (odpowiednik case
poza procesem) tzn. przypisanie warunkowe i selektywne
*Konstrukcja “wait” tylko symulacja!!!
*Przypisanie wartości zmiennej “:=“
*Pętla “while”
Zasady ogólne:
* VHDL nie rozróżnia dużych i małych liter (ale należy mieć na
uwadze tzw. dobry styl)
* średnik kończy wyrażenie (zakończenie linii programu)
* każda linia komentarza rozpoczyna się od “--”
* identyfikatory muszą zaczynać się od litery i zawierać na
następnych pozycjach znaki alfanumeryczne lub pokreślenie “_”
* język silnie zorientowany na typ, automatyczna konwersja należy
do rzadkości, możliwe jest przeciążanie operatorów, funkcji,
procedur
* syntezowalny jest jedynie podzbiór języka
* żaden z systemów EDA nie gwarantuje prawidłowej syntezy
modelowania algorytmicznego
* wielkość układu po syntezie nie ma nic wspólnego z objętością
kodu (należy zrezygnować z finezyjnego zapisu!!!)
Opis układu/podukładu składa się z deklaracji jednostki (ENTITY) i
jednego lub więcej bloków ARCHITECTURE opisującego
działanie. ENTITY zawiera listę zacisków wejściowych i
wyjściowych (PORTS), jest ekwiwalentem symbolu na schemacie
entity model_name is
port (
list of inputs and outputs (P_I_xxx, P_O_xxx, P_IO_xxx)
);
end model_name;
architecture arch_name(a) of model_name is
begin
.....
VHDL concurrent statements
.....
end arch_name(a);
when -else
library IEEE;
use IEEE.std_logic_1164.all;
entity mux2to1 is
port (
P_I_S
:in
P_I_X0
:in
P_I_X1
:in
P_O_Y
:out
);
end mux2to1;
std_logic;
std_logic_vector(7 downto 0);
std_logic_vector(7 downto 0);
std_logic_vector(7 downto 0) --brak średnika!!!
architecture a of mux2to1 is
begin
P_I_Y <= P_I_X1 when (P_I_S=‘1’)
else P_I_X1;
end a;
* LIBRARY -biblioteka to zbiór zanalizowanych jednostek projektowych
przechowywany w danym systemie operacyjnym (nazwa logiczna a nie katalog w
systemie!)
* aby można się było odwoływać do elementów biblioteki należy użyć klauzuli
USE (specyfikuje które pakiety -package będą wybrane z biblioteki)
use IEEE.std_logic_1164.all
importuje procedury, funkcje i definicje pakietu std_logic_1164
* Pakiet std_logic_1164 definiuje system logiczny 9-wartościowy, 4 wartości są
przydatne dla syntezy: ‘1’, ‘0’, ‘Z’ (high impedance), ‘-’ (don’t care),
pozostałe wartości używane są dla celów symulacji:
‘U’ (uninitialized), ‘X’ (unknown-strong drive), ‘W’,’L’,’H’ (unknown, logic 0,
logic 1 -weak drive).
Dwa typy danych: std_ulogic oraz std_logic -z dodatkową funkcją rozstrzygającą
konflikty połączeń (resolution function). Zalecane jest używanie typu std_logic!
Przykład: sygnał y ma dwa sterowniki (driver’y)
y<=a;
y<=b;
* typ std_logic jest pojedynczym bitem, std_logic_vector jest używany do
definiowania magistral
* VHDL posiada wbudowany typ bit 2-wartościowy ‘1’ i ‘0’; jest on
niewystarczający do syntezy; istnieje też typ bit_vector
* na liście portów podajemy końcówki zewnętrzne układu w konwencji:
nazwa tryb
typ
dla celów syntezy używa się trybów in, out, inout
słowo signal jest opcjonalne -najczęściej w deklaracji portów opuszczane
* szerokość magistrali można definiować z indeksem rosnącym lub malejącym
std_logic_vector (7 downto 0) lub std_logic_vector(0 to 7)
skutek: różny wynik operacji przypisania
np. y<=“11110000” (wektory piszemy w podwójnym cudzysłowiu), jest
równoważne operacjom:
y(7)<=‘1’; ... ; y(0)<=‘0’; lub y(0)<=‘1’; ... ; y(7)<=‘0’;
* indeks elementu magistrali może mieć dowolną wartość całkowitą
* można użyć w opisie układu poszczególnych elementów magistali
y(5 downto 2)<=“0110”;
UWAGA: kierunek indeksowania musi być zgodny z deklaracją magistrali
y(5 downto 3)<=x(0 to 2);
oznacza przypisanie y(5)<=x(0); y(4)<=x(1); y(3)<=x(2);
* jeżeli przypisujemy wartość całej magistrali wówczas nie trzeba specyfikować
indeksów np. y<=x1; szerokość magistrali po obu stronach musi być identyczna!!!
* operator sklejania & (concatenation), np. dla deklaracji:
signal a
:
std_logic_vector(7 downto 0);
signal b
:
std_logic_vector(3 downto 0);
możliwe jest przypisanie
a <= “100” & b & ‘1’;
* ogólna postać warunkowego przypisania sygnału:
signal_name <= value1 when condition1
else value2 when condition2
....
else valueN when conditionN
else default_value;
warunki są wyrażeniami przyjmującymi wartości true/false
* wynik syntezy:
Multiplekser 2/1 -metoda równań kombinacyjnych
library IEEE;
use IEEE.std_logic_1164.all;
entity mux2to1 is
port (
P_I_S
:in
P_I_X0
:in
P_I_X1
:in
P_O_Y
:out
);
end mux2to1;
std_logic;
std_logic_vector(7 downto 0);
std_logic_vector(7 downto 0);
std_logic_vector(7 downto 0)
architecture a of mux2to1 is
signal SIG_TMP: std_logic_vector(7 downto 0);
begin
SIG_TMP<=(others=>P_I_S);
P_O_Y<=(SIG_TMP and P_I_X1) or (not SIG_TMP and P_I_X0);
end a;
* sygnał P_I_S (port wejściowy) nie może być bezpośrednio użyty w operacjach
logicznych z sygnałami P_I_X0 i P_I_X1 ze względu na różny typ (std_logic,
std_logic_vector)
* zadeklarowano sygnał wewnętrzny -wektor/magistralę; deklaracje sygnałów
umieszcza się zawsze przed słowem kluczowym begin
* w deklaracji sygnału wewnętrznego nie określa się trybu (in, out, inout)
* typ sygnału SIG_TMP jest zgodny z P_I_X0 i P_I_X1 (ta sama szerokość
wektora!!!)
* każdemu bitowi wektora SIG_TMP przypisano stan portu wejściowego P_I_S
SIG_TMP <= (others=>P_I_S);
--najprostszy zapis (aggregate)
SIG_TMP<= P_I_S & P_I_S & P_I_S & P_I_S & P_I_S & P_I_S & P_I_S
& P_I_S;
SIG_TMP(0)<=P_I_S;
.....
SIG_TMP(7)<=P_I_S;
SIG_TMP(2 downto 0)<= (others=>P_I_S);
SIG_TMP(3)<=P_I_S;
Multiplekser 2/1 -użycie procesu kombinacyjnego/niezegarowanego
architecture a of mux2to1 is
begin
comb: process (s, x0, x1)
begin
if (s=‘1’) then
y<= x1;
else
y<=x0;
end if;
end process comb;
end a;
* proces jest częścią kodu VHDL wykonywaną (analizowaną) sekwencyjnie; proces
traktowany jako całość wykonywany jest współbieżnie z innymi procesami w
architekturze oraz z innymi instrukacjami współbieżnymi; w obrębie procesu
dozwolone jest stosowanie wyłącznie instrukcji sekwencyjnych
* zmiana wartości któregokolwiek sygnału umieszczonego na liście czułości procesu
powoduje analizę jego kodu przez symulator
* w procesach kombinacyjnych na liście czułości należy umieścić wszystkie (!!!)
sygnały pobudzające blok logiki kombinacyjnej, który ma być efektem syntezy
procesu
s
x0(7)
x1(7)
y(7)
* w zależności od stanu sygnału s wyjście y powtarza zmiany na liniach x0 lub x1
* proces musi być analizowany gdy:
(1) zachodzą zmiany wartości wektora x0 oraz s=0,
(2) zachodzą zmiany wartości wektora x1 oraz s=1,
(3) zmienia się wartość sygnału s.
* przypisanie nowej wartości do sygnału następuje w chwili wyjścia symulatora z
procesu;
*w trakcie analizy kodu procesu rozpisywana jest tzw. transakcja; faktyczne
przypisanie następuje z opóźnieniem delta, odpowiadającym najmniejszemu
kwantowi czasu symulacyjnego (jeżeli nie wskazano inaczej!)
np:
process(a,b,c,out1,out2)
begin
out1<=a and b;
out2<=out1 xor c;
out3<=out1 xor out2;
end process
czas
t1
t2
t2+d
t2+2d
t2+3d
a
0
1
1
1
1
b
1
1
1
1
1
c
1
1
1
1
1
out1 out2 out3
0
1
1
0->1 1
1
1
1->0 1->0
1
0
0->1
1
0
1
* wniosek: pomimo że proces jest kodem sekwencyjnym, to kolejność umieszczenia
przypisań do sygnałów jest dowolna
Przykład pętli -opis behawioralny enkodera priorytetowego
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity en_prior is
port( P_I_X :in std_logic_vector(1 to 7);
P_O_ENC
:out std_logic_vector(2 downto 0)
); end en_prior;
architecture a of en_prior is
begin
process(P_I_X)
variable v_i: integer;
--definicja zmiennej
begin
i:=7;
--przypisanie wartości do zmiennej
l1: while (i>0 and P_I_X(i)/=‘1’) loop
i:=i-1;
end loop;
P_O_ENC<=conv_std_logic_vector(i,3); --na drugim miejscu podana liczba pozycji
end process;
--wektora wynikowego
end a;
* zdefiniowano zmienną typu integer, przypisania do zmiennej dokonuje się przy
pomocy operatora :=
* zmienne użyte w procesie są widoczne tylko w obrębie tego procesu; przechowują
swoje wartości w trakcie “uśpienia” procesu
* przypisanie nowej wartości do zmiennej następuje natychmiast -w momencie analizy
linii przez symulator, np:
process(a,b,c)
variable out1,out2:std_logic;
begin
out1:=a and b;
out2:=out1 xor c;
out3<=(not out1) and out2;
end process;
czas
t1
t2
t2+d
t3
t4
t4+d
a
0
1
1
1
1
1
b
1
1
1
0
0
0
c out1 out2 out3
1
0
1
1
1
1
0
1->0
1
1
0
0
0
0
0
0
1
0
1
0->1
1
0
1
1
* istotna jest kolejność wykonania przypisań, nowa wartość zmiennej jest
uwzględniania w następnych liniach procesu
•użyto funkcji konwersji integer -> std_logic_vector zdefiniowanej w pakiecie
std_logic_arith
* typy pętli (podsumowanie):
prosta
L1:loop
do_something;
end loop L1;
z określonym schematem iteracji
L2:for I in 1 to 3 loop
A(I)<=B(I);
end loop L2;
L3:while condition loop
do_something;
end loop L3;
* instrukcje używane w połączeniu z pętlami (symulacja!!!):
next
np:
next L1 when I=J;
next when (B<10);
exit
np:
exit L2;
exit Loop3 when a>b;
*podstawowym warunkiem syntezowalności kodu z użyciem pętli jest ustalona na
etapie syntezy liczba wykonań pętli
* zaleca się stosowanie atrybutów do specyfikacji zakresu pętli
Przykład pętli w układzie kombinacyjnym -opis syntezowalny
ENTITY proc IS
PORT(
P_I_D
: IN BIT_VECTOR (2 DOWNTO 0);
P_O_Q
: OUT INTEGER RANGE 0 TO 3
); END proc;
ARCHITECTURE a OF proc IS
BEGIN
PROCESS (P_I_D)
--zliczanie jedynek logicznych w słowie wejściowym
VARIABLE v_num_bits : INTEGER;
BEGIN
v_num_bits := 0;
FOR i IN P_I_D'RANGE LOOP --atrybut RANGE, zmienna i zdefiniow.
automatycznie
IF P_I_D(i) = '1' THEN
v_num_bits := _vnum_bits + 1;
END IF;
END LOOP;
q <= v_num_bits;
END PROCESS;
END a;
Dekoder 3 na 8
entity dec3to8 is port(
P_I_SEL :in std_logic_vector(2 downto 0);
--wejścia
P_I_ENA:in std_logic;
--output enable
P_O_Y
:out std_logic_vector(7 downto 0)
--wyjścia aktywne stanem
niskim
); end dec3to8;
architecture a of dec3to8 is
begin
procd:process(P_I_SEL,P_I_ENA)
begin
P_O_Y<=“1111_1111”;
--wartość domyślna
if (P_I_ENA=‘1’) then
case P_I_SEL is
when “000”=> P_O_Y(0)<=‘0’; when “001”=> P_O_Y(1)<=‘0’;
when “010”=> P_O_Y(2)<=‘0’; when “011”=> P_O_Y(3)<=‘0’;
when “100”=> P_O_Y(4)<=‘0’; when “101”=> P_O_Y(5)<=‘0’;
when “110”=> P_O_Y(6)<=‘0’; when “111”=> P_O_Y(7)<=‘0’;
end case;
end if;
end process procd;
end a;
* wersja prawidłowa
* wersja bez wartości domyślnej;
generowane są przerzutniki typu latch
* użyto wyrażenia sekwencyjnego case dozwolonego wyłącznie w procesach
* w wyrażeniu case można przypisać wartość domyślną używając konstrukcji
when OTHERS => .........
* wersja alternatywna z użyciem przypisania warunkowego osobno dla każdego bitu
architecture d2 of dec3to8 is
begin
y(0)<=‘0’ when (ena=‘1’ and sel=“000”) else ‘1’;
y(1)<=‘0’ when (ena=‘1’ and sel=“001”) else ‘1’;
y(2)<=‘0’ when (ena=‘1’ and sel=“010”) else ‘1’;
y(3)<=‘0’ when (ena=‘1’ and sel=“011”) else ‘1’;
y(4)<=‘0’ when (ena=‘1’ and sel=“100”) else ‘1’;
y(5)<=‘0’ when (ena=‘1’ and sel=“101”) else ‘1’;
y(6)<=‘0’ when (ena=‘1’ and sel=“110”) else ‘1’;
y(7)<=‘0’ when (ena=‘1’ and sel=“111”) else ‘1’;
end d2;
* indeksowanie przez sygnał-niezbędna funkcja konwersji znajduje się w pakiecie
std_logic_unsigned;
process (sel, ena)
begin
y<=“11111111”; --wartość domyślna
if (ena=‘1’) then y(conv_integer(sel))<=‘0’; end if;
end process;
GENERACJA (generate)
* jest odpowiednikiem pętli we współbieżnej części kodu
* służy do automatycznej generacji struktur regularnych, tworzonych na bazie
struktury wzorcowej (fizyczny efekt => powielenie podukładów wzorcowych)
* wewnątrz generate może być powielana dowolna instrukcja współbieżna łącznie z
samą instrukcją generate
* dwa schematy generacji: generacja for dla układów w pełni regularnych,
generacja if gdy istnieją nieregularności w układzie
* wymagana jest etykieta (label) generacji
* przykład:
pełny sumator
wielobitowy
entity fulladder_n is
generic (size : integer := 4 );
port(
P_I_A
:in std_logic_vector(size-1 downto 0);
P_I_B
:in std_logic_vector(size-1 downto 0);
P_O_SUM :out std_logic_vector(size-1 downto 0);
P_I_CIN : in std_logic;
P_O_COUT:out std_logic);
end fulladder_n;
architecture a of fulladder_n is
signal
SIG_C
:std_logic_vector(size downto 0);
begin
SIG_C(0)<=P_I_CIN;
G: for i in 0 to size-1 generate
P_O_SMU(i)<=P_I_A(i) xor P_I_B(i) xor SIG_C(i);
SIG_C(i+1)<=(P_I_A(i) and P_I_B(i)) or (P_I_A(i) and SIG_C(i)) or (P_IB_(i) and SIG_C(i));
end generate;
P_O_COUT<=SIG_C(size);
end a;
* parametr generacji nie musi być deklarowany (tutaj i)
Projektowanie hierarchiczne (opis strukturalny)
* w opisie układu przywołujemy wcześniej zdefiniowane jednostki projektowe,
dołączając sygnały do odpowiednich portów tych jednostek (tworzenie powiązań)
* typy i zakresy sygnałów aktualnych i lokalnych (w przywoływanych jednostkach)
muszą być zgodne
* przy tworzeniu powiązań między portami obowiązuje zgodność kierunków
(trybów)
•przywołanie komponentu może również ustalać wartości parametrów ogólnych
* przyłączenia sygnałów do końcówek komponentu można dokonywać w dowolnej
kolejności, ale z przywołaniem nazwy portu:
fa2: fulladder port map(b=>b(2),a=>a(2),sum=>sum(2),cout=>c2,cin=>c1);
* specyfikacja parametrów ogólnych
-w deklaracji komponentu:
component bufor
generic (size:integer:=8);
port(
P_I_A:in std_logic_vector(size-1 downto 0);
P_O_Y:out std_logic_vector(size-1 downto 0) );
end component;
-w podstawieniu komponentu
buf1: bufor
generic map(size=>8)
port map(a=>port_in,y=>port_out);
Układy sekwencyjne
Przerzutniki typu zatrzask (latch) aktywne poziomem
* zatrzask jest elementem pamiętającym
latch: process(enable,data)
begin
if (enable=‘1’) then
q<=data;
end if;
end process latch;
enable
data
q
process(enable,data)
begin
if (enable=‘1’) then
q<=data;
else
q<=‘0’;
end if;
end process; -- q<=enable and data;
zatrzask (latch) z resetem asynchronicznym i synchronicznym
process(enable,data,rst)
begin
if (rst=‘1’) then
q1<=‘0’;
elsif (enable=‘1’) then
q1<=data;
end if;
end process;
enable
rst
data
q
q1
q2
process(enable,data,rst)
begin
if (enable=‘1’) then
if (rst=‘1’) then
q2<=‘0’;
else
q2<=data;
end if;
end if;
end process;
process(clk)
begin
if (clk’event and clk=‘1’) then
q<=data;
end if;
end process;
if (clk’event and clk=‘0’) then
* po warunku testującym zbocze zegara nie może wystąpić żadna gałąź else lub elsif
* dla większości kompilatorów wykrywanie zbocza zegarowego musi być jedynym
testowanym w danym wyrażeniu warunkiem -niedopuszczalne jest łączenie z
testowaniem innego sygnału
* jeżeli wykrywanie zbocza zegara następuje w wyrażeniu if... , to sygnał zegarowy
musi(!!!) być umieszczony na liście wrażliwościowej procesu
* proces może opisywać układ reagujący na zbocze tylko jednego sygnału (brak
fizycznych elementów sterowanych zboczami wielu sygnałów)
•możliwy jest opis w części współbieżnej kod
przerzutniki z synchronicznym lub asynchronicznym
zerowaniem/ustawianiem/ładowaniem
process(clk)
begin
if (clk’event and clk=‘1’) then
if (clear=‘1’) then
q1<=‘0’;
else
q1<=data;
end if;
end if;
end process;
process(clk,clear)
begin
if (clear=‘1’) then
q2<=‘0’
elsif (clk’event and clk=‘1’) then
q2<=data;
end if;
end process;
process(clk,load,data_lo)
begin
if (load=‘1’) then --asynchroniczne ładowanie nowej zawartości data_lo
q<=data_lo;
elsif (clk’event and clk=‘1’) then --testowanie narastającego zbocza clk
q<=data;
end if;
end process;
process(clk,reset)
begin
if (reset=‘0’) then
--asynchroniczne zerowanie
q<=‘0’;
elsif (clk’event and clk=‘1’) then
if (load=‘1’) then --multiplekser przełączający wejścia data_lo i data
q<=data_lo;
else
q<=data;
end if;
end if;
end process;
* wykorzystując pakiet std_logic_1164 można wykrywać zbocza przy pomocy funkcji
if rising_edge(clk) then ....
lub
if falling_edge(clk) then .....
* wykorzystanie wejścia clock enable (wybrane technologie) oraz bramkowanie zegara (gated
clock -uwaga, niebezpieczeństwo powstania szpilek na linii zegara)
process(clk)
begin
if rising_edge(clk) then
if (clk_enable=‘1’) then
q<=data;
end if;
end if;
end process;
process(clk,gate)
begin
if (gate=‘1’) then
if falling_edge(clk) then
q<=data;
end if;
end if;
end process;
liczniki synchroniczne
entity counter is
port ( P_I_CLK
:in std_logic;
P_I_CLEAR
: in_std_logic;
P_I_LOAD
: in std_logic;
P_I_ENA
: in std_logic;
P_I_UP_DOWN :in std_logic; --zliczanie w góre (1) lub w dół (0)
P_I_DATA_IN
:in integer range 0 to 255;
P_O_COUNT
:out integer range 0 to 255);
if (P_I_CLEAR=‘1’) then
end counter;
v_cnt:=0;
architecture a of counter is
elsif rising_edge(clk) then
begin
if (P_I_ENA=‘1’) then
process(P_I_CLK, P_I_CLEAR, P_I_UP_DOWN
if (P_I_LOAD=‘1’) then
variable v_cnt
:integer range 0 to 255;
v_cnt:=P_DATA_IN;
variable v_dir
:integer;
else
begin
v_cnt:=v_cnt+v_dir;
if (P_I_UP_DOWN=‘1’) then
end if;
v_dir:=1;
end if;
else
end if;
v_dir:=-1;
P_O_COUNT <= v_cnt;
end if;
end process;
end a;
* kierunek zliczania =>sumator wartości bieżącej rejestru z liczbą 00000001 (+1) lub
11111111 (-1),
ena=‘1’, load=‘0’ => zwiększona lub zmniejszona wartość podana na wejścia D
przerzutników
* ena=‘0’ => przepisywana jest wartość bieżąca przerzutników (brak modyfikacji)
* ena, load=‘1’ => na wejścia przerzutników podawana jest wartość data_in
* asynchroniczne zerowanie - clear podane bezpośrednio do przerzutników
ograniczenie zakresu zliczania
entity counter is
port(
clk, preset
:in std_logic;
count
:out std_logic_vector(7 downto 0) );
end counter;
architecture behave of counter is
signal count_int :std_logic_vector(7 downto 0);
constant load_value
:std_logic_vector(7 downto 0):=X”80”;
constant high_value
:integer:=220;
begin
process(clk,preset)
count<=count_int;
begin
end behave;
if (preset=‘1’) then
count_int<=load_value;
* korzystanie z funkcji
elsif rising_edge(clk) then
konwersji conv_integer oraz
if (conv_integer(count_int)=high_value) then
przeciążonego operatora
count_int<=X”00”;
dodawania wymaga użycia
else
pakietu std_logic_unsigned
count_int<=count_int+’1’;
end if;
* dodawanie wektorów:
end if;
count_int + ”00000001”
end process;
początek ramki
Dzielniki częstotliwości
rejestry przesuwne
* syntezowane jako łańcuch przerzutników
process(clk,reset)
begin
if (reset=‘1’) then
a<=‘0’; b<=‘0’; c<=‘0’; shift_out<=‘0’;
elsif (clk’event and clk=‘1’) then
a<=shift_in; b<=a; c<=b; shift_out<=c;
end if;
end process;
* operacja na typie
signal data_in, shiftreg :std_logic_vector(7 downto 0);
process(clk)
begin
if (clk’event and clk=‘1’) then
if (load=‘1’) then
shiftreg<=data_in;
--wpis równoległy
else
shiftreg(0)<=shift_in;
shiftreg(7 downto 1)<=shiftreg(6 downto 0); (SPI!!!!!)
end if;
--shiftreg(7)=shift_out jest wyjściem
end if;
end process;
automaty/maszyny stanów (FSM -Finite State Machine)
* złożony układ cyfrowy, który na podstawie własnego stanu bieżącego oraz stanu
wejść przechodzi do stanu następnego; przejście to jest reakcją na zbocze zegara
* automat jawny => liczba stanów jest znana, każdy stan jest nazwany, rejestry
przechowują zakodowaną reprezentację stanu
* opis automatów zawiera sekcję kombinacyjną i sekcję synchroniczną
* automat Moore’a: wyjścia automatu są jedynie funkcją stanu, logika kombinacyjna
służy do generowania sygnałów wyjściowych na podstawie stanu automatu, oraz do
określenia wejść przerzutników na podstawie stanu automatu i wejść do układu
* automat Mealy’ego: zarówno następny stan jak i wektor wyjść są funkcjami
bieżącego stanu automatu oraz wektora wejść; automat Mealy’ego synchroniczny
wyposażony jest w przerzutniki wyjściowe, automat asynchroniczny natychmiast
reaguje na zmianę sygnałów wejściowych
* kodowanie stanów:
-użycie typu wyliczeniowego
-użycie stałych
type state is (st0, st1, st2, st3, st4);
signal present_state, next_state: state;
subtype state is std_logic_vector(3 downto 0);
constant st0: state:=“0010”;
constant st1: state:=“1000”;
entity MOORE is
port (X, clock
:in bit;
Z
:out bit);
end MOORE;
architecture b1 of MOORE is
type STATE_TYPE is (S0,S1,S2,S3);
signal CURRENT, NEXTS: STATE_TYPE;
begin
Current
state
S0
S1
S2
S3
Next
Output
state
(Z)
X=0 X=1
S0
S2
0
S0
S2
1
S2
S3
1
S3
S1
0
SYNCH:process(clock)
begin
if (clock’event and clock=‘1’) then
CURRENT<=NEXTS;
end if;
end process SYNCH;
COMB:process(CURRENT,X)
begin
case CURRENT is
when S0=> Z<=‘0’;
if (X=‘0’) then NEXTS<=S0;
else NEXTS<=S2;
end if;
when S1=> Z<=‘1’;
if (X=‘0’) then NEXTS<=S0;
else NEXTS<=S2;
end if;
when S2=> Z<=‘1’;
if (X=‘0’) then NEXTS<=S2;
else NEXTS<=S3;
end if;
when S3=> Z<=‘0’;
if (X=‘0’) then NEXTS<=S3;
else NEXTS<=S1;
end if;
end case;
end process COMB;
end b1;
* przypisania do sygnału Z utworzą po
syntezie logikę kombinacyjną zależną od
wyjść przerzutników przechowujących
aktualny stan automatu
* przypisania do sygnału NEXTS opisują
logikę kombinacyjną przygotowującą wejścia
dla przerzutników przechowujących stan:
następny stan (NEXTS) jest funkcją
aktualnego stanu (CURRENT) i wejścia
* proces SYNCH opisuje zespół
przerzutników o wektorze wejściowym
NEXTS i wyjściowym CURRENT
* liczba przerzutników jest zależna od
kodowania stanów; o sposobie kodowania
decyduje narzędzie syntezy (sekwencyjne,
gray, one-hot, one-cold)
architecture b2 of MOORE is
type STATE_TYPE is (S0,S1,S2,S3);
signal CURRENT: STATE_TYPE;
begin
SYNCH:process(clock)
begin
if (clock’event and clock=‘1’) then
case CURRENT is
when S0=> if (X=‘1’) then CURRENT<=S2;
end if;
when S1=> if (X=‘0’) then CURRENT<=S0;
else CURRENT<=S2;
end if;
when S2=> if (X=‘1’) then CURRENT<=S3;
end if;
when S3=> if (X=‘1’) then CURRENT<=S1;
end if;
end case;
end if;
end process SYNCH;
COMB:process(CURRENT)
begin
case CURRENT is
when S0=> Z<=‘0’;
when S1=> Z<=‘1’;
when S2=> Z<=‘1’;
when S3=> Z<=‘0’;
end case;
end process COMB;
end b2;
* proces SYNCH opisuje tylko
przejścia między stanami, jego
rezultatem jest zespół
przerzutników wraz z logiką
sterującą ich wejściami
* proces COMB opisuje logikę
kombinacyjną sterującą wyjściem
automatu
architecture b3 of MOORE is
type STATE_TYPE is (S0,S1,S2,S3);
signal CURRENT: STATE_TYPE;
begin
* wyjście Z jest synchronizowane zegarem,
zrealizowane za pomocą logiki kombinacyjnej
i przerzutnika
* cel zmiany: likwidacja stanów nieustalonych
(w poprzednich rozwiązaniach możliwość
powstania szpilek przy zmianie stanu
automatu), uniezależnienie od sposobu
kodowania stanów
SYNCH:process(clock)
begin
if (clock’event and clock=‘1’) then
case CURRENT is
when S0=> if (X=‘1’) then CURRENT<=S2; Z<=‘1’;
end if;
when S1=> if (X=‘0’) then CURRENT<=S0; Z<=‘0’;
else CURRENT<=S2; Z<=‘1’;
end if;
when S2=> if (X=‘1’) then CURRENT<=S3; Z<=‘0’;
end if;
when S3=> if (X=‘1’) then CURRENT<=S1; Z<=‘1’;
end if;
end case;
end if;
end process SYNCH;
end b3;
Current
state
S0
S1
S2
S3
Next
Output
state
(Z)
X=0 X=1 X=0 X=1
S0
S2
0
1
S0
S2
0
0
S2
S3
1
0
S3
S1
0
1
entity MEALY is
port (X, clock, reset :in bit;
Z :out bit); end MEALY;
architecture m1 of MEALY is
type STATE is array(3 downto 0) of bit;
signal CURRENT, NEXTS: STATE;
-- one hot encoding
constant S0: STATE:=“0001”;
constant S1: STATE:=“0010”;
constant S2: STATE:=“0100”;
constant S3: STATE:=“1000”;
signal Zint:bit;
begin
--Z<=Zint; --autom. Mealy’ego asynchron.
SYNCH:process(clock,reset)
begin
if (reset=‘1’) then CURRENT<=S0;Z<=‘0’;
elsif (clock’event and clock=‘1’) then
CURRENT<=NEXTS;
Z<=Zint; --autom. Mealy’ego synchr.
end if;
end process SYNCH;
COMB:process(CURRENT,X)
begin
case CURRENT is
when S0=> if (X=‘0’) then NEXTS<=S0; Zint<=‘0’;
else NEXTS<=S2; Zint<=‘1’;
end if;
when S1=> if (X=‘0’) then NEXTS<=S0; Zint<=‘0’;
else NEXTS<=S2; Zint<=‘0’;
end if;
when S2=> if (X=‘0’) then NEXTS<=S2; Zint<=‘1’;
else NEXTS<=S3; Zint<=‘0’;
end if;
when others=> if (X=‘0’) then NEXTS<=S3; Zint<=‘0’;
else NEXTS<=S1; Zint<=‘1’;
end if;
end case;
end process COMB;
end m1;
--others obejmuje S3
--i stany nielegalne
* zalecanym sposobem opisu automatów jest rozdzielenie części kombinacyjnej i rejestrowej
MAGISTRALE
entity bus_proj is port(
P_I_RNW
:in std_logic;
P_IO_DATA
:inout std_logic_vector(7 downto 0);
P_O_DATA
: out std_logic_vector(7 downto 0);
P_I_DATA
:in std_logic_vector(3 downto 0)
);
end bus_proj;
architecture a of bus_proj is
begin
P_IO_DATA <= P_I_DATA when (P_I_RNW='0’)
else "ZZZZZZZZ";
process(P_I_CLK)
begin
if rising_edge(P_I_CLK) then
if P_I_RNW = ‘1’ then
P_O_DATA <= P_IO_DATA;
end if;
end process;
end process;
end a;
function <FUNC_NAME> (<comma_separated_inputs> : <type>;
<comma_separated_inputs> : <type>) return <type> is
-- subprogram_declarative_items (constant declarations, variable
declarations, etc.)
begin
-- function body
end <FUNC_NAME>;
function FUNC_GET_NUM(width : natural ; count : natural) return natural is
constant CON_BITS : natural := width*count ;
constant CON_NUM : natural := width*count/16 ;
begin
if CON_BITS > CON_NUM*16 then
return (CON_NUM+1)*16-CON_BITS ;
else
return 0 ;
end if ;
end function ;
INST_DSER0: entity work.ENT_DESERIALIZER
generic map (
GEN_DATA_WIDTH => GEN_DATA_WIDTH_OUT0,
GEN_DATA_REST => FUNC_GET_NUM(GEN_DATA_WIDTH_OUT0,1),
GEN_DATA_COUNT => 1
)
port map (
P_I_CLK
=> P_I_CLK,
P_I_RESET => not SIG_SYNCH(0),
P_O_DATA
P_O_DRY
=> P_O_DATA(CON_LEFT_OUT0 downto CON_RIGHT_OUT0),
=> P_O_DRY(0),
P_I_FIFO_DATA => SIG_DSER_FIFO_DATA(17 downto 0),
P_O_FIFO_RD => SIG_DSER_FIFO_RD(0),
P_I_FIFO_EMPTY => SIG_DSER_FIFO_EMPTY(0)
);
function FUNC_GET_NUM(width : natural ; count : natural) return natural is
constant CON_BITS : natural := width*count ;
constant CON_NUM : natural := width*count/16 ;
begin
if CON_BITS > CON_NUM*16 then
return (CON_NUM+1)*16-CON_BITS ;
else
return 0 ;
end if ;
end function ;
TYPY OBIEKTÓW W VHDL -PODSUMOWANIE
* typy skalarne
-typ całkowity -definiowany do wykonywania działań matematycznych, w standardzie
zapisywany na 32 bitach: od -231 do +(231-1)
przykłady literałów całkowitych o podstawie 10: 0, 100, 1e6, -700000, 1_945_690
binarnych: ”1111”
heksalnych: X”F”
prawidłowe są przypisania do zmiennych lub sygnałów:
x:=1; y<=-7; d:=1e4
przypisanie nieprawidłowe:
z<=10.0;
-typ rzeczywisty - zakres zdefiniowany przez standard: -1.0e38 do 1.0e38
przykłady literałów rzeczywistych: 100.0, -1.765, 2.234_567_78, 2.71e-9
binarnych: 2#1.101#e3 (13.0), 2#11.00_01_11#
heksalnych: 16#F.F#e1 (255.0)
prawidłowe przypisania wartości:
x:=2.34; y<=3.14159; z<=1.9e21;
symualcje!!!!
przypisania nieprawidłowe:
x:=2; y<=-1;
-typ wyliczeniowy: definiujemy go poprzez wymienienie wszystkich elementów,
nazwa elementów jest dowolna
type meal is (breakfast, dinner, lunch, midnight_snack);
W systemie każdy z elementów typu wyliczeniowego otrzymuje wewnętrzny
identyfikator w postaci liczby całkowitej począwszy od 0 dla skrajnego lewego
elementu. Wyjątek: kodowanie stanów one hot lub one cold.
-typ fizyczny -niesyntezowalny
predefiniowanym w standardzie typem fizycznym jest TIME, jednostką bazową jest
fs (można używać jednostek pochodnych ps, ns, us, ms, s)
przykład użycia: t:=5 ns;
przykład nowej definicji type weight is range 0 to 1e15
units
ug;
mg=1000 ug;
g=1000 mg;
kg=1000 g;
t=1000 kg;
end units;
* typy złożone
-typy tablicowe: grupują obiekty tego samego typu (dowolnego) w jeden obiekt, w
ogólności tablice mogą być wielowymiarowe
wymiar tablicy: typu całkowitego lub wyliczeniowego, indeks rosnący (to) bądź
malejący (downto)
typ tablicowy ograniczony: dokładnie podany jest zakres indeksów
typ nieograniczony: zakres nie jest podany, można definiować wiele podtypów na
bazie jednej definicji typu
type tab1 is array (0 to 7) of integer;
type tab2dim is array (0 to 7, 15 downto 0) of std_logic;
type std_logic_vector is array (NATURAL range<>) of std_logic; -użyty zakres musi
być podany w oddzielnej definicji
dostęp do tablicy poprzez indeks elementu: y<=x(6);
możliwe przypisanie pełnej tablicy przy pomocy agregatu
-rekordy: grupują elementy różnych typów, mogą zawierać wewnątrz tablice i inne
rekordy; do elementu rekordu odwołujemy się poprzez nazwę pola
type rec_type is record
val_int :integer;
val_log :std_logic;
end record;
signal x: rec_type;
.........
x.val_int<=1;
x.val_log<=‘0’;
możliwe przypisanie przy pomocy agregatu: x<=(1,’0’);
x<=(val_log=>’0’, val_int=> 1);
TYPY PREDEFINIOWANE -w pakietach STANDARD oraz TEXTIO
* BOOLEAN -wyliczeniowy, dwie wartości false i true (false<true)
* BIT -wyliczeniowy, dwie wartości ‘0’ i ‘1’
* CHARACTER -wyliczeniowy, zawiera zbiór znaków ASCII, znaki w pojedynczym
cudzysłowiu (‘a’, ‘Y’, ‘x’)
* INTEGER -liczby całkowite
* NATURAL -zbiór liczb nieujemnych, podtyp INTEGER
* POSITIVE -zbiór liczb dodatnich, podtyp INTEGER
* BIT_VECTOR -tablica wartości typu BIT
łańcuchy bitów: “1110”, B”1111_1110”, X”FC0”, O”7677”
* STRING -tablica wartości typu CHARACTER
łańcuchy znaków: “ala ma kota”, “symulacja”
* REAL -zbiór liczb rzeczywistych
* TIME -typ fizyczny reprezentujący czas symulacji
TYPY PAKIETU STD_LOGIC_1164
* STD_ULOGIC, STD_LOGIC (z dodatkową funkcją arbitrażową)
type STD_ULOGIC is (‘U’, ‘X’, ‘0’, ‘1’, ‘Z’, ‘W’, ‘L’, ‘H’, ‘-’);
* STD_ULOGIC_VECTOR, STD_LOGIC_VECTOR -typy tablicowe nieogr.
ATRYBUTY
* atrybut jest dodatkową informacją związaną z obiektem
* przykłady predefiniowanych atrybutów dla sygnałów:
clk’event, clk’stable
* przykłady atrybutów predefiniowanych dla typów tablicowych oraz sygnałów i
zmiennych typu tablicowego:
type ADDRESS_TYPE is std_logic_vector(31 downto 0);
signal address : ADDRESS_TYPE;
address’left
->31
-zwraca wartość lewego indeksu
address’right
->0
-zwraca wartość prawego indeksu
address’low
->0
-zwraca wartość najmniejszego indeksu
address’high
->31
-zwraca wartość największego indeksu
address’range
->zakres 0 do 31 -zwraca zakres zmian indeksu
ADDRESS_TYPE’ascending - >false -zwraca true lub false w zależności od kierunku
zmian indeksów
* użytkownik może definiować własne atrybuty, które są stałymi
Dziękuję za uwagę
1) Struktura projektu
2) Debugowanie (CS Pro)
3) DCM
4) State machine
5) FIFO with indpendend clocks
6) Dual Port Memory (DPM) with independent clocks