VHDL - praktyka, ۞ Nauka i Technika, Informatyka, Programowanie, Kurs VHDL


» Wstęp «

Projekty tu prezentowane są to jedne z najprostszych i najpopularniejszych struktur, toteż lepiej można poznać funkcjonowanie języka VHDL w opisywaniu układów cyfrowych. A mając do dyspozycji wiedzę na temat tworzenia tak prostych struktur, możemy pokusić się o tworzenie bardziej lub bardzo zaawansowanych struktur (język VHDL znalazł zastosowanie do opisu mikroprocesorów, pamięci, itp.)

Projekty te zostały tak stworzone, aby pokazać jednocześnie drogę jaką podążała technologia, od prostych bramek logicznych do jednostki arytmetyczno- logicznej. Droga ta może pokrywać się z programem nauczania dla Pracowni Elektrycznej i Elektronicznej.

» Bramki logiczne «

Początek formularza

Bramkami nazywane są kombinacyjne układy cyfrowe, realizujące proste funkcje logiczne jednej lub wielu zmiennych logicznych. W praktyce są one realizowane przez specjalne układy, które zwykle zawierają w sobie cztery bramki jednego typu. Z pomocą języka VHDL jesteśmy w stanie stworzyć projekt układu cyfrowego, który zastąpiłby szereg różnych układów specjalistycznych i realizował wszystkie najpopularniejsze funkcje logiczne.

Projekt 'BramkiLogiczne' został tak zaprojektowany, aby spełniał dowolną funkcję logiczną na dwóch wejściowych zmiennych logicznych 'A' i 'B' (wyjątkiem jest negacja jednej zmiennej 'A') i prezentował wynik na wyjściu 'Y'.

Dół formularza

W jednej, określonej chwili projekt może realizować tylko jedną operację, którą wybieramy na podstawie wartości sygnału 'wybierz'. Dodatkowo każdy z projektów został wyposażony w sygnał 'reset', który pozwala na sterowanie nim przez inną jednostkę projektową np.: mikroprocesor.

W projekcie zostały zaprezentowane następujące bramki logiczne:

a. bramka NOT
b. bramka AND
c. bramka NAND
d. bramka OR
e. bramka NOR
f. bramka XOR
g. bramka NXOR

a. bramka NOT

Bramka ta (dostępna w projekcie 'Bramki' po podaniu wartości "000" na port 'wybierz') jest układem o jednym wejściu realizującym operację negacji zmiennej wejściowej tzn. zmieniającym wartość zmiennej na jej dopełnienie. Negacja oznacza, że gdy sygnał wejściowy ma wartość 0, to wyjściowy 1, i odwrotnie: gdy sygnał wejściowy jest 1 to wyjściowy 0.

A

Y

0

1

1

0

0x01 graphic

b. bramka AND

Bramka ta (dostępna w projekcie 'Bramki' po podaniu wartości "001" na port 'wybierz') jest układem o dwu lub większej liczbie wejść, realizującym funkcję iloczynu logicznego zmiennych wejściowych. Funkcja iloczynu przyjmuje wartość 1 gdy wszystkie składniki mają wartość 1. W pozostałych przypadkach wartość funkcji wynosi 0.

A

B

Y

0

0

0

0

1

0

1

0

0

1

1

1

0x01 graphic

c. bramka NAND

Bramka ta (dostępna w projekcie 'Bramki' po podaniu wartości "010" na port 'wybierz') jest układem realizującym funkcję negacji iloczynu logicznego zmiennych wejściowych, a więc zgodnie z prawem de Morgana również funkcje sumy negacji zmiennych wejsciowych. Funkcja negacji iloczynu przyjmuje wartość 1 gdy wszystkie składniki mają wartość 0. W pozostałych przypadkach wartość funkcji wynosi 1.

A

B

Y

0

0

1

0

1

1

1

0

1

1

1

0

0x01 graphic

d. bramka OR

Bramka ta (dostępna w projekcie 'Bramki' po podaniu wartości "011" na port 'wybierz') jest układem o dwu lub większej liczbie wejść, realizującym funkcję sumy logicznej zmiennych wejściowych. Funkcja sumy logicznej przyjmuje wartość 1 gdy którykolwiek składnik funkcji (sygnał wejściowy) ma wartość 1; 0 - gdy wszystkie składniki maja wartość 0.

A

B

Y

0

0

0

0

1

1

1

0

1

1

1

1

0x01 graphic

e. bramka NOR

Bramka (dostępna w projekcie 'Bramki' po podaniu wartości "100" na port 'wybierz') ta jest układem realizującym funkcję negacji sumy logicznej zmiennych wejściowych, a więc zgodnie z prawem de Morgana również funkcje iloczynu negacji zmiennych wejsciowych. Funkcja negacji sumy logicznej przyjmuje wartość 1 gdy którykolwiek składnik funkcji (sygnał wejściowy) ma wartość 0; 1 - gdy wszystkie składniki maja wartość 0.

A

B

Y

0

0

1

0

1

0

1

0

0

1

1

0

0x01 graphic

f. bramka XOR

Bramka ta (dostępna w projekcie 'Bramki' po podaniu wartości "101" na port 'wybierz') realizuje dodawanie mod 2, tj. na jej wyjściu pojawi się '1'-ka logiczna wtedy i tylko wtedy, gdy suma arytmetyczna zmiennych wejściowych będzie równa '1'.

A

B

Y

0

0

0

0

1

1

1

0

1

1

1

0

0x01 graphic

g. bramka NXOR

Bramka ta (dostępna w projekcie 'Bramki' po podaniu wartości "110" na port 'wybierz') jest negacją bramki XOR, zatem na jej wyjściu pojawi się '1'-ka logiczna wtedy i tylko wtedy, gdy suma arytmetyczna zmiennych wejściowych będzie równa '0'.

A

B

Y

0

0

1

0

1

0

1

0

0

1

1

1

0x01 graphic

Kod źródłowy

entity BramkiLogiczne is
port ( reset, A, B : in bit; wybierz : in bit_vector (2 downto 0) ; Y : out bit );
end entity;

architecture ArchBramkiLogiczne of BramkiLogiczne is
begin
process (reset, A, B, wybierz)
begin
if (reset = '0') then
case wybierz is

-- realizacja bramki NOT ;
when "000" => Y <= not A;

-- realizacja bramki AND ;
when "001" => Y <= A and B;

-- realizacja bramki NAND ;
when "010" => Y <= A nand B;

-- realizacja bramki OR ;
when "011" => Y <= A or B;

-- realizacja bramki NOR ;
when "100" => Y <= A nor B;

-- realizacja bramki XOR ;
when "111" => Y <= A xor B;

-- realizacja bramki NXOR ;
when "110" => Y <= not (A xor B);

-- opcja dla pozostałych wartości sygnału wybierz ;
when others => null;

end case;
else
Y <= '0';
end if;
end process;
end architecture;

» Przerzutniki asynchroniczne «

Początek formularza

Przerzutnik to podstawowy element układów sekwencyjnych, którego podstawową funkcją jest pamiętanie jednego bitu informacji. Posiada on conajmniej dwa wejścia i z reguły dwa wyjścia. Wejścia mogą być:

  • zegarowe, zwane synchronizującymi albo wyzwalającymi - gdy impuls zegarowy występuje, przerzutnik reaguje na informację wejściową; w przypadku braku wejścia zegarowego, przerzutnik reaguje zawsze gdy zmieni się informacja wejściowa,

  • informacyjne - w zależności od nich przerzutnik odpowiednio generuje sygnały wyjściowe,

  • programujące - są to zwykle dwa wejścia: ustawiające S (gdy występuje to przerzutnik jest włączony), zerujące R (gdy występuje to przerzutnik zostaje wyzerowany).

Dół formularza

Istnieje wiele typów przerzutników, a co za tym idzie wiele różnych układów cyfrowych realizujących określony typ przerzutnika. Dlategoteż można pokusić się o stworzenie jednego uniwersalnego układu, który pokazywałby działanie wszystkich najpopularniejszych przerzutników.

W ten sposób, dzięki językowi VHDL, możemy zrealizować projekt 'Przerzutniki', który zawierałby w sobie:

a. przerzutnik RS
b. przerzutnik JK
c. przerzutnik D
d. przerzutnik T

a. przerzutnik asynchroniczny RS

Przerzutnik RS (dostępny w projekcie 'Przerzutniki' po podaniu wartości "00" na port 'wybierz') jest najprostszym przerzutnikiem. Posiada on dwa wejścia informacyjne R i S (w projekcie 'Przerzutniki' odpowiednio Y i X przy wybierz = "00") i zależnie od trzech dozwolonych kombinacji ich stanów, przerzutnik może spełniać trzy funkcje:

Przy stanie R = S = '1' stan wyjściowy przerzutnka jest nieokreślony co oznacza, że może zaistnieć albo stan Q = '0' i nieQ = '1', albo Q = '1' i nieQ = '0'.

Sn

Rn

Qn+1

0

0

Qn

0

1

0

1

0

1

1

1

?

0x01 graphic

b. przerzutnik asynchroniczny JK

Przerzutnik ten (dostępny w projekcie 'Przerzutniki' po podaniu wartości "01" na port 'wybierz') różni się od przerzutnika RS tym, że stan J = '1' i K = '1' (w naszym projekcie odpowiednio X = '1' i Y = '1' przy wybierz = "01") jest dozwolony. Przerzutnik JK jest przerzutnikiem najbardziej uniwersalnym funkcjonalnie. Warto zauważyć, że jeśli J = K = '1', to stany na wyjściach Q i nieQ zmieniają się na przeciwne. Przypadek ten odpowiada dzieleniu liczby impulsów zegarowych przez dwa - jest to dwójka licząca.

Jn

Kn

Qn+1

0

0

Qn

0

1

0

1

0

1

1

1

nieQn

0x01 graphic

c. przerzutnik asynchroniczny D

Przerzutnik D (dostępny w projekcie 'Przerzutniki' po podaniu wartości "10" na port 'wybierz') jest dość prostym przerzutnikiem, posiadającym tylko jedno wejście informacyjne D (w naszym projekcie X przy wybierz = "10"). Działanie jego polega na wpisaniu '0' na wyjście Q i '1' na nieQ, gdy sygnał wejściowy D jest równy '0', a wpisanie '1' na wyjście Q i '0' na nieQ, gdy sygnał wejściowy D jest równy '1'. Należy tu zauważyć, że informacje wyjściowe (Qn+1 i nieQn+1) nie są zależne od wsześniejszych (Qn i nieQn).

Dn

Qn+1

0

0

1

1

0x01 graphic

d. przerzutnik asynchroniczny T

Przerzutnik T (dostępny w projekcie 'Przerzutniki' po podaniu wartości "11" na port 'wybierz') jest także prostym przerzutnikiem. Posiada tylko jedno wejście informacyjne T (w naszym projekcie X przy wybierz = "11"). Działanie jego polega na zmianie sygnałów wyjściowych na przeciwne przy T = '1', a pozostawieniu ich bez zmian przy T = '0'. Podobnie jak w przypadku przerzutnika JK realizuje on dwójkę liczącą.

Tn

Qn+1

0

Qn

1

nieQn

0x01 graphic

Kod źródłowy

entity Przerzutniki is
port ( reset, X, Y : in bit ; wybierz : in bit_vector (1 downto 0) ; Q, nieQ: out bit );
end entity;

architecture ArchPrzerzutniki of Przerzutniki is
signal wynik : bit_vector (1 downto 0);
signal temp : bit;
begin
process (reset, X, Y, wybierz, wynik)
begin
if (reset = '0') then
case wybierz is

-- realizacja przerzutnika RS ;
when "00" =>
wynik(1) <= X or (not Y and wynik(1));
wynik(0) <= not wynik(1);

-- realizacja przerzutnika JK ;
when "01" =>
wynik(1) <= (not wynik(1) and X) or (not Y and wynik(1));
wynik(0) <= not wynik(1);

-- realizacja przerzutnika D ;
when "10" =>
wynik(1) <= X;
wynik(0) <= not wynik(1);

-- realizacja przerzutnika T ;
when "11" =>
wynik(1) <= wynik(1) xor X;
wynik(0) <= not wynik(1);

end case;
else
wynik <= "00";
end if;
Q <= wynik(1);
nieQ <= wynik(0);
end process;
end architecture;

» Układy rejestrowe «

Rejestrem nazywamy układ służący do przechowywania informacji. Ze względu na sposób wprowadzania i wyprowadzania informacji rejestry dzielą się na:

  • szeregowe, umożliwiające szeregowe wprowadzenie i wyprowadzenie informacji, tzn. kolejno, bit po bicie,

  • szeregowo-równoległe, umożliwiające szeregowe wprowadzenie i równoległewyprowadzenie informacji,

  • równoległo-szeregowe, umożliwiające równoległe wprowadzenie i szeregowe wyprowadzenie informacji,

  • równoległe, umożliwiające równoległe wprowadzenie i wyprowadzenie informacji jednocześnie do wszystkich i ze wszystkichpozycji rejestru.

Jeśli zatem chcemy skonstruować jakieś urządzenie wykorzystujące rejestry, jesteśmy "uzależnieni" od konkretnego typu rejestru. Dzięki językowi VHDL można ten problem rozwiązać projektując jeden uniwersalny projekt 'Rejestry', który w zależności od podanej wartości sygnału 'wybierz' zastąpi nam wybrany rejestr (dla 'wybierz' = "00" - szeregowy, "01" - szeregowo-równoległy, "10" - równoległo-szeregowy, "11" - równoległy).

Obsługa takiego uniwersalnego rejestru jest stosunkowo prosta.

Zapis do rejestru: Najpierw wybieramy typ rejestru, którego chcemy użyć. Następnie dane wejściowe, które podamy na port 'wej' (dla rejestrów z wprowadzaniem szeregowym używamy tylko jednej linii sygnału 'wej'). Pozostaje nam tylko wybrać opcję zapisu na porcie 'ster' i uruchomić układ. Zauważyć należy, że wszelkie operacje realizowane przez projekt 'Rejestry' są wykonywane w obecności sygnału zegarowego 'clk' (wyjątkiem jest asynchroniczny sygnał 'reset', który zeruje cały rejestr).

Odczyt rejestru: Już zapisany rejestr możemy odczytać. Robimy to za pomocą zmiany sygnału 'ster' na opcję odczytu. Wynik odczytu pojawi się na porcie wyjściowym 'wyj' w postaci charakterystycznej dla danego typu rejestru.

Uwaga: W między czasie możemy obserwować sygnał wewnętrzny 'rejestr', ale jest to możliwe tylko w procesie symulacji projektu. Po zaprogramowaniu układu cyfrowego oczywiście nie będzie on dostępny.

Kod źródłowy

entity Rejestry is
port ( reset, clk, ster : in bit;
wybierz : in bit_vector(1 downto 0);
wej : in bit_vector(3 downto 0);
wyj : out bit_vector(3 downto 0) );
end entity;

architecture ArchRejestry of Rejestry is
signal rejestr : bit_vector(3 downto 0);
begin
process (reset, clk, ster)
begin
if reset = '0' then
case wybierz is

-- realizacja rejestru szeregowego ;
when "00" =>
if ster = '1' and clk = '1' and clk'event then
rejestr(0) <= wej(0);
elsif ster = '1' and clk = '0' and clk'event then
rejestr <= rejestr sll 1;
elsif ster = '0' and clk = '1' and clk'event then
wyj(0) <= rejestr(0);
elsif ster = '0' and clk = '0' and clk'event then
rejestr <= rejestr rol 1;
end if;
wyj(3 downto 1) <= "000";

-- realizacja rejestru szeregowo-równoległego ;
when "01" =>
if ster = '1' and clk = '1' and clk'event then
rejestr(0) <= wej(0);
elsif ster = '1' and clk = '0' and clk'event then
rejestr <= rejestr sll 1;
elsif ster = '0' and clk = '1' and clk'event then
wyj <= rejestr;
end if;

-- realizacja rejestru równoległo-szeregowego ;
when "10" =>
if ster = '1' and clk = '1' and clk'event then
rejestr <= wej;
elsif ster = '0' and clk = '1' and clk'event then
wyj(0) <= rejestr(0);
elsif ster = '0' and clk = '0' and clk'event then
rejestr <= rejestr rol 1;
end if;

-- realizacja rejestru równoległego ;
when "11" =>
if ster = '1' and clk = '1' and clk'event then
rejestr <= wej;
elsif ster = '0' and clk = '1' and clk'event then
wyj <= rejestr;
end if;

end case;
else
rejestr <= "0000";
wyj <= "0000";
end if;
end process;
end architecture;

» Liczniki asynchroniczne «

Licznikiem nazywany jest sekwencyjny układ cyfrowy służący do zliczania i pamiętania liczby impulsów podawanych w określonym przedziale czasu na jego wejście zliczające. Jeśli chcelibyśmy sklasyfikować liczniki, możemy to zrobić np. pod względem ich długości cyklu, która to może być stała lub programowalna.

Działanie projektu 'Liczniki' polega na zliczaniu impulsów wejściowych i prezentowaniu wyniku na porcie wyjściowym. Proces zliczania jest jednak uzależniony od dwóch sygnałów: sterującego 'wybierz' (który określa typ wykorzystywanego licznika) i zerującego 'reset' (który zeruje wyjścia licznika).

Projekt 'Liczniki' został przystosowany do pracy jako trzy różne liczniki:

a. licznik modulo 2
b. licznik modulo 3
c. licznik modulo 4

a. licznik asynchroniczny modulo 2

0x01 graphic

Licznik asynchroniczny modulo 2 jest realizowany przez projekt 'Liczniki' po podaniu wartości "00" na port 'wybierz'. Działanie jego polega na zliczaniu imulsów wejściowych do dwóch, tzn. wynikiem zliczania jest wartość 0 lub 1 zapisana w postaci bitowej (0 = "00", 1 = "01") na portach wyjściowych.

b. licznik asynchroniczny modulo 3

0x01 graphic

Licznik asynchroniczny modulo 3 jest realizowany przez projekt 'Liczniki' po podaniu wartości "01" na port 'wybierz'. Działanie jego polega na zliczaniu imulsów wejściowych do trzech, tzn. wynikiem zliczania jest wartość 0, 1 lub 2 zapisana w postaci bitowej (0 = "00", 1 = "01", 2 = "10") na portach wyjściowych.

c. licznik asynchroniczny modulo 4

0x01 graphic

Licznik asynchroniczny modulo 4 jest realizowany przez projekt 'Liczniki' po podaniu wartości "10" na port 'wybierz'. Działanie jego polega na zliczaniu imulsów wejściowych do czterech, tzn. wynikiem zliczania jest wartość 0, 1, 2 lub 3 zapisana w postaci bitowej (0 = "00", 1 = "01", 2 = "10", 3 = "11") na portach wyjściowych.

Kod źródłowy

entity Liczniki is
port ( reset, wej : in bit; wybierz : in bit_vector (1 downto 0); wyjA, wyjB : out bit );
end entity;

architecture ArchLiczniki of Liczniki is
signal wynik : bit_vector (1 downto 0);
begin
process (reset, wynik, wej)
begin
if reset = '0' then
case wybierz is

-- realizacja licznika modulo 2
when "00" =>
if wej = '0' and wej'event then
wynik(0) <= ('1' and not wynik(0)) or ('0' and wynik(0));
end if;
wynik(1) <= '0';

-- realizacja licznika modulo 3
when "01" =>
if wej = '0' and wej'event then
wynik(0) <= (not wynik(1) and not wynik(0)) or ('0' and wynik(0));
wynik(1) <= (wynik(0) and not wynik(1)) or ('0' and wynik(1));
end if;

-- realizacja licznika modulo 4
when "10" =>
if wej = '0' and wej'event then
wynik(0) <= ('1' and not wynik(0)) or ('0' and wynik(0));
if wynik(0) = '1' then
wynik(1) <= ('1' and not wynik(1)) or ('0' and wynik(1));
end if;
end if;

-- opcja dla pozostałych wartości sygnału wybierz ;
when others => null;

end case;
else
wynik <= "00";
end if;
wyjA <= wynik(0);
wyjB <= wynik(1);
end process;
end architecture;

» Układy arytmetyczne «

Sumator jest to podstawowy układ arytmetyczny. Jego zasadniczym zadaniem jest dodawanie liczb, ale zastosowanie sumatora można także wykorzystać do odejmowania liczb. Dzieje się tak ponieważ odejmowanie to także rodzaj dodawania. Sumatory realizujące funkcję odejmowania liczb nazywają się subtraktorami.

Projekt 'Arytmetyka' realizuje funkcję sumatora i subtraktora 4-bitowych liczb. Działanie jego polega na podaniu wartości sygnałów wejściowych ('wejA', 'wejB') i wyborze funkcji ('wybierz' = '0' - dodawanie, '1' - odejmowanie). Wynik zostaje prezentowany na porcie wyjściowym ('wyj').

Dodatkowy port wyjściowy 'przen' służy do określenia, czy operacja spowodowała przepełnienie tzn. dla dodawania wystąpiło przeniesienie, a dla odejmowania potrzebna jest pożyczka.

a. sumator

Sumator (dostępny w projekcie 'Arytmetyka' po podaniu wartości '0' na port 'wybierz') realizuje dodawanie, które wykonuje się według tych samych zasad, jakimi posługujemy się przy dodawaniu liczb dziesiętnych. W przypadku dodawania wielobitowych liczb dwójkowych należy uwzględnić przeniesienie z pozycji sąsiedniej mniej znaczącej od rozpatrywanej. Funkcje, które realizuje sumator wyglądają następująco:

Si = Ai xor Bi xor Ci-1
C
i = Ai.Bi + (Ai xor Bi)Ci-1

Dodajna

Ai

0

0

0

0

1

1

1

1

Dodajnik

Bi

0

0

1

1

0

0

1

1

Przeniesienie

Ci-1

0

1

0

1

0

1

0

1

Suma

Si

0

1

1

0

1

0

0

1

Przeniesienie

Ci

0

0

0

1

0

1

1

1

b. subtraktor

Subtraktor (dostępny w projekcie 'Arytmetyka' po podaniu wartości '1' na port 'wybierz') realizuje odejmowanie. Tak jak w przypadku dodawania, funkcja odejmowania wielobitowych liczb dwójkowych także odbywa się na zasadach normalnego odejmowania liczb dziesiętnych i podobnie jak tam należy uwzględnić pożyczkę z pozycji mniej znaczącej od rozpatrywanej. Funkcje, które realizuje subtraktor wyglądają następująco:

Di = Ai xor Bi xor Vi-1
V
i = notAi.Bi + (notAi xor Bi)Vi-1

Odjemna

Ai

0

0

0

0

1

1

1

1

Odjemnik

Bi

0

0

1

1

0

0

1

1

Pożyczka

Vi-1

0

1

0

1

0

1

0

1

Różnica

Di

0

1

1

0

1

0

0

1

Pożyczka

Vi

0

1

1

1

0

0

0

1

Kod źródłowy

entity Arytmetyka is
port ( reset, wybierz : in bit; wejA, wejB : bit_vector (3 downto 0);
wyj : out bit_vector (3 downto 0); przep : out bit );
end entity;

architecture ArchArytmetyka of Arytmetyka is
signal dane, wynik : bit_vector (7 downto 0);
signal zapas : bit;
begin
process (reset, wejA, wejB, dane, wynik)
begin
dane <= wejA & wejB;
if (reset = '0') then
case wybierz is

-- realizacja dodawania 4-bitowych liczb (sumator) ;
when '0' =>
wynik(4) <= dane(0) xor dane (4);
wynik(0) <= dane(0) and dane(4);
wynik(5) <= (not wynik(1) and (dane(1) or dane(5) or wynik(0))) or (dane(1) and dane(5) and wynik(0));
wynik(1) <= (dane(1) and dane(5)) or (dane(1) and wynik(0)) or (dane(5) and wynik(0));
wynik(6) <= (not wynik(2) and (dane(2) or dane(6) or wynik(1))) or (dane(2) and dane(6) and wynik(1));
wynik(2) <= (dane(2) and dane(6)) or (dane(2) and wynik(1)) or (dane(6) and wynik(1));
wynik(7) <= (not wynik(3) and (dane(3) or dane(7) or wynik(2))) or (dane(3) and dane(7) and wynik(2));
wynik(3) <= (dane(3) and dane(7)) or (dane(3) and wynik(2)) or (dane(7) and wynik(2));

-- realizacja odejmowania 4-bitowych liczb (subtraktor) ;
when '1' =>
if wejA < wejB then
zapas <= '1';
else
zapas <= '0';
end if;
wynik(0) <= (not dane(4) and dane(0)) or ((not dane(4) xor dane(0)) and zapas);
wynik(1) <= (not dane(5) and dane(1)) or ((not dane(5) xor dane(1)) and wynik(0));
wynik(2) <= (not dane(6) and dane(2)) or ((not dane(6) xor dane(2)) and wynik(1));
wynik(3) <= (not dane(7) and dane(3)) or ((not dane(7) xor dane(7)) and wynik(2));
wynik(4) <= dane(4) xor dane(0) xor zapas;
wynik(5) <= dane(5) xor dane(1) xor wynik(0);
wynik(6) <= dane(6) xor dane(2) xor wynik(1);
wynik(7) <= dane(7) xor dane(3) xor wynik(2);

end case;
else
wynik <= "00000000";
end if;
wyj <= wynik (7 downto 4);
przep <= wynik (3);
end process;
end architecture;

» Konwertery kodów «

Konwertery kodów służą przede wszystkim do komunikacji między dwoma urządzeniami lub też urządzeniem i człowiekiem. Przedstawiony projekt 'Konwertery' jest przystosowany do pracy w różnych kodach, zatem jego zastosowanie może być bardziej wszechstronne. Projekt może pełnić funkcję trzech różnych konwerterów. Może pracować jako:

Wybór odpowiedniego trybu pracy odbywa się przez podanie odpowiedniej wartości na port 'wybierz'. Dodatkowo w prezentacji został umieszczony przykład zastosowania traskodera, który jest możliwy do zrealizowania po podłączeniu zestawu diod LED do zaprojektowanego układu cyfrowego.

a. dekoder

Jest to konwerter, w którym kod wyjściowy jest kodem pierścieniowym, tzn. "1 z n". W projekcie 'Konwertery' jest on dostępny po podaniu wartości "00" na port 'wybierz'.

wej

wyj

00000000

00000001

00000001

00000010

00000010

00000100

00000011

00001000

00000100

00010000

00000101

00100000

00000110

01000000

00000111

10000000

inny

00000000

   

b. enkoder

Jest to konwerter, w którym kod wejściowy jest kodem pierścieniowym, tzn. "1 z n". W projekcie 'Konwertery' jest on dostępny po podaniu wartości "01" na port 'wybierz'.

wej

wyj

00000001

00000000

00000010

00000001

00000100

00000010

00001000

00000011

00010000

00000100

00100000

00000101

01000000

00000110

10000000

00000111

inny

11111111

   

c. transkoder

Jest to konwerter, w którym kod wejściowy i wyjściowy nie jest kodem pierścieniowym. W projekcie 'Konwertery' jest on dostępny po podaniu wartości "10" na port 'wybierz'.

wej

wyj

00000000

11111100

00000001

01100000

00000010

11011010

00000011

11110010

00000100

01100110

00000101

10110110

00000110

00111110

00000111

11100000

00001000

11111110

00001001

11100110

inny

00000001

Kod źródłowy

entity Konwertery is
port ( reset : in bit; wybierz : in bit_vector(1 downto 0);
wej : in bit_vector (7 downto 0);
wyj : out bit_vector (7 downto 0) );
end entity;

architecture ArchKonwertery of Konwertery is
begin
process (reset, wej)
begin
if (reset = '0') then
case wybierz is

-- realizacja dekodera ;
when "00" =>
case wej is
when "00000000" => wyj <= "00000001";
when "00000001" => wyj <= "00000010";
when "00000010" => wyj <= "00000100";
when "00000011" => wyj <= "00001000";
when "00000100" => wyj <= "00010000";
when "00000101" => wyj <= "00100000";
when "00000110" => wyj <= "01000000";
when "00000111" => wyj <= "10000000";
when others => wyj <= "00000000";
end case;

-- realizacja enkodera ;
when "01" =>
case wej is
when "00000001" => wyj <= "00000000";
when "00000010" => wyj <= "00000001";
when "00000100" => wyj <= "00000010";
when "00001000" => wyj <= "00000011";
when "00010000" => wyj <= "00000100";
when "00100000" => wyj <= "00000101";
when "01000000" => wyj <= "00000110";
when "10000000" => wyj <= "00000111";
when others => wyj <= "11111111";
end case;

-- realizacja transkodera ;
when "10" =>
case wej is
when "00000000" => wyj <= "11111100";
when "00000001" => wyj <= "01100000";
when "00000010" => wyj <= "11011010";
when "00000011" => wyj <= "11110010";
when "00000100" => wyj <= "01100110";
when "00000101" => wyj <= "10110110";
when "00000110" => wyj <= "00111110";
when "00000111" => wyj <= "11100000";
when "00001000" => wyj <= "11111110";
when "00001001" => wyj <= "11100110";
when others => wyj <= "00000001";
end case;

-- opcja dla pozostałych wartości sygnału wybierz ;
when others => null;

end case;
else
wyj <= "00000000";
end if;
end process;
end architecture;

» Jednostka arytmetyczno-logiczna «

Jednostki arytmetyczne są to uniwersalne, programowalne układy realizujące szereg różnych operacji arytmetycznych i logicznych. Zademonstrowany projekt 'ALU' realizuje szesnaście operacji arytmetycznych i szesnaście logicznych na dwu 4-bitowych słowach wejściowych ('wejA', 'wejB'), które realizowane są w zależności od sygnałów sterujących. Są to sygnały:

  • 'rodzaj_pracy' - służy do wyboru realizowanych operacji, dla '0' - arytmetycznych, dla '1' - logicznych,

  • 'wej_przenieś' - służy do określenia przeniesienia wejściowego (sygnał dostępny tylko dla operacji arytmetycznych),

  • 'ster' - służy do precyzyjnego określenia jednej z 16 operacji wybranych uprzednio przy pomocy sygnałów 'rodzaj_pracy' i 'wej_przenies',

Wynik jest prezentowany na porcie 'wyj'. Warto dodać, że pojawi się on tam tylko przy braku sygnału zerującego 'reset'.

A oto jakie operacje są realizowane przez projekt 'ALU':
(dodawanie arytmetyczne jest oznaczone jako "plus", logiczne "+")

'rodzaj_pracy'

'wej_przenies'

'ster'

realizowana funkcja

0

0

0000

F = A

0

0

0001

F = A+B

0

0

0010

F = A+nieB

0

0

0011

F = minus 1 (uzup. do 2)

0

0

0100

F = A plus AnieB

0

0

0101

F = A+B plus AnieB

0

0

0110

F = A minus B minus 1

0

0

0111

F = AnieB minus 1

0

0

1000

F = A plus AB

0

0

1001

F = A plus B

0

0

1010

F = (A+nieB) plus AB

0

0

1011

F = AB minus 1

0

0

1100

F = A plus A

0

0

1101

F = (A+B) plus A

0

0

1110

F = (A+nieB) plus A

0

0

1111

F = A minus 1

0

1

0000

F = A plus 1

0

1

0001

F = A+B plus 1

0

1

0010

F = A+nieB plus 1

0

1

0011

F = zero

0

1

0100

F = A plus AnieB plus 1

0

1

0101

F = (A+B) plus AnieB plus 1

0

1

0110

F = A minus B

0

1

0111

F = AnieB

0

1

1000

F = A plus AB plus 1

0

1

1001

F = A plus B plus 1

0

1

1010

F = (A+nieB) plus AB plus 1

0

1

1011

F = AB

0

1

1100

F = A plus A plus 1

0

1

1101

F = (A+B) plus A plus 1

0

1

1110

F = (A+nieB) plus A plus 1

0

1

1111

F = A

1

X

0000

F = nieA

1

X

0001

F = nie(A+B)

1

X

0010

F = nieAB

1

X

0011

F = 0

1

X

0100

F = nie(AB)

1

X

0101

F = nieB

1

X

0110

F = AxorB

1

X

0111

F = AnieB

1

X

1000

F = nieA+B

1

X

1001

F = nie(AxorB)

1

X

1010

F = B

1

X

1011

F = AB

1

X

1100

F = 1

1

X

1101

F = A+nieB

1

X

1110

F = A+B

1

X

1111

F = A

Uwaga: W powyższej prezentacji przedstawiono tylko najważniejsze elementy funkcjonowania ALU. W projekcie przewidzianych jest jeszcze kilka dodatkowych funkcji. Są to: określenie przeniesienia wyjściowego ('wyj_przenies'), przeniesienia wyjściowego generowanego ('wyj_przenies_g'), przeniesienia wyjściowego propagowanego ('wyj_przenies_p'), a także wyjścia komparatora słów danych ('AB').

Kod źródłowy

entity ALU is
port ( reset, wej_przenies, rodzaj_pracy : in bit;
wejA, wejB, ster : in bit_vector (3 downto 0);
wyj : out bit_vector (3 downto 0);
wyj_przenies, wyj_przenies_p, wyj_przenies_g, AB : out bit
);
end entity;

architecture ArchALU of ALU is
signal temp : bit_vector (15 downto 0);
signal wynik : bit_vector (3 downto 0);
begin
process (reset, wejA, wejB, ster, wej_przenies, rodzaj_pracy, temp, wynik)
begin
if reset = '0' then
temp(0) <= (wejB(3) and ster(3) and wejA(3)) nor (wejA(3) and ster(2) and not wejB(3));
temp(1) <= not ((not wejB(3) and ster(1)) or (ster(0) and wejB(3)) or wejA(3));
temp(2) <= (wejB(2) and ster(3) and wejA(2)) nor (wejA(2) and ster(2) and not wejB(2));
temp(3) <= not ((not wejB(2) and ster(1)) or (ster(0) and wejB(2)) or wejA(2));
temp(4) <= (wejB(1) and ster(3) and wejA(1)) nor (wejA(1) and ster(2) and not wejB(1));
temp(5) <= not ((not wejB(1) and ster(1)) or (ster(0) and wejB(1)) or wejA(1));
temp(6) <= (wejB(0) and ster(3) and wejA(0)) nor (wejA(0) and ster(2) and not wejB(0));
temp(7) <= not ((not wejB(0) and ster(1)) or (ster(0) and wejB(0)) or wejA(0));
temp(8) <= not temp(0) nor temp(1);
temp(9) <= not temp(2) nor temp(3);
temp(10) <= not temp(4) nor temp(5);
temp(11) <= not temp(6) nor temp(7);
temp(12) <= not (temp(1) or (temp(0) and temp(3)) or (temp(0) and temp(2) and temp(5)) or (temp(0) and temp(2) and temp(4) and temp(7)));
temp(13) <= not ((not wej_przenies and temp(6) and temp(4) and temp(2) and not rodzaj_pracy) or (temp(4) and temp(2) and temp(7) and not rodzaj_pracy) or (temp(2) and temp(5) and not rodzaj_pracy) or (temp(3) and not rodzaj_pracy));
temp(14) <= not ((not wej_przenies and temp(6) and temp(4) and not rodzaj_pracy) or (temp(4) and temp(5) and not rodzaj_pracy) or (temp(5) and not rodzaj_pracy));
temp(15) <= (not wej_przenies and temp(6) and not rodzaj_pracy) nor (temp(7) and not rodzaj_pracy);
wyj_przenies_g <= temp(12);
wyj_przenies_p <= not (temp(0) and temp(2) and temp(4) and temp(6));
wyj_przenies <= temp(12) nand not (temp(0) and temp(2) and temp(4) and temp(6) and wej_przenies);
AB <= wynik(3) and wynik(2) and wynik(1) and wynik(0);
wynik(3) <= temp(8) xor temp(13);
wynik(2) <= temp(9) xor temp(14);
wynik(1) <= temp(10) xor temp(15);
wynik(0) <= temp(11) xor (not wej_przenies nand not rodzaj_pracy);
elsif reset = '1' then
wynik <= "0000"; wyj_przenies <= '0';
wyj_przenies_p <= '0'; wyj_przenies_g <= '0';
AB <= '0';
end if;
wyj <= wynik;
end process;
end architecture;

» Pamięć «

Pamięć RAM umożliwia zapis informacji i jej odczyt bez niszczenia zapisanej uprzednio informacji. Podstawową komórką pamięci RAM stanowi przerzutnik RS sterowany sygnałem adresu ('adres') oraz sygnałem danych ('dane'). Istnieje jeszcze jeden sygnał charakterystyczny dla rejestrów pamięci. Jest to oczywiście sygnał sterujący odczytem i zapisem ('ster').

Działanie prostej pamięci RAM realizuje projekt 'Pamiec4x4', który zawiera cztery 4-bitowe rejestry równoległe. W zależności od sygnałów sterujących będą zapisywane dane do rejestrów. I tak, jeśli sygnał 'ster' będzie równy '0' nastąpi zapis, jesli '1' - odczyt. Operacje te muszą jednak być poprzedzone wyborem odpowiedniej komórki pamięci. Robi się to za pomocą sygnału 'adres'. Jeśli 'adres' będzie równy "00" to operacje będą się odbywały na rejestrze 'pamiec(0)', jeśli "01" - 'pamiec(1)', jeśli "10" - 'pamiec(2) i w końcu "11" - pamiec(3). Należy jednak pamiętać, że wszystkie operacje mogą być zrealizowane tylko w obecności sygnału zegarowego 'clk' i wyłączonym sygnale zerującym 'reset'.

Kod źródłowy

entity Pamiec4x4 is
port ( reset, clk, ster : in bit; adres : in bit_vector (1 downto 0);
dane : in bit_vector (3 downto 0);
wyj : out bit_vector (3 downto 0) );
end entity;

architecture ArchPamiec4x4 of Pamiec4x4 is
type rejestry is array (3 downto 0) of bit_vector (3 downto 0);
signal pamiec : rejestry;
begin
process (reset, clk, ster, dane)
begin
if reset = '0' and ster = '1' and clk = '1' and clk'event then
case adres is
when "00" => pamiec(0) <= dane;
when "01" => pamiec(1) <= dane;
when "10" => pamiec(2) <= dane;
when "11" => pamiec(3) <= dane;
end case;
elsif reset = '0' and ster = '0' and clk = '1' and clk'event then
case adres is
when "00" => wyj <= pamiec(0);
when "01" => wyj <= pamiec(1);
when "10" => wyj <= pamiec(2);
when "11" => wyj <= pamiec(3);
end case;
elsif reset = '1' then
for wybor in 0 to 3 loop
pamiec(wybor) <= "0000";
end loop;
wyj <= "0000";
end if;
end process;
end architecture;



Wyszukiwarka

Podobne podstrony:
VHDL, ۞ Nauka i Technika, Informatyka, Programowanie, Kurs VHDL
metody numeryczne - interpolacja, Nauka i Technika, Informatyka, Programowanie
WŁASNY SERWER FTP WINDOWS XP, ۞ Nauka i Technika, Informatyka, Systemy operacyjne, OS MS Windows, Si
metody numeryczne - interpolacja, Nauka i Technika, Informatyka, Programowanie
Turbo Pascal kurs, Technik Informatyk, Programowanie strukturalne i obiektowe Turbo Pascal
mgr.inż - Internet jako źródło informacji dla elektroenergetyki, ۞ Nauka i Technika, Elektrotechnika
2008-probny-praktyka-teleinformatyk-wlasny, Technik Informatyk, materialy egzamin teoretyczny
konspekt-Dydaktyka Informatyki, Edukacja techniczno informatyczna, Programowanie obiektowe, sieci la
prezentacja konrad, NAUKA, Technikum informatyczne, Język polski
Na stanowisku eksploatacji w zakresie elektroenergetycznym, ۞ Nauka i Technika, Elektrotechnika, Bez
RYSUNKI-charakterystyki maszyn elektrycznych, ۞ Nauka i Technika, Elektrotechnika, Maszyny elektrycz
C++ informacje, Technik Informatyk, PROGRAMOWANIE
Bierny filtr harmonicznych prądu AHF 005 i AHF 010 firmy Danfoss, ۞ Nauka i Technika, Elektrotechnik
SCIAGI, NAUKA, Technikum informatyczne, Język polski
HAMOWANIE SILNIKA, ۞ Nauka i Technika, Elektrotechnika, Maszyny elektryczne
Budowa maszyn indukcyjnych 2, ۞ Nauka i Technika, Elektrotechnika, Maszyny elektryczne

więcej podobnych podstron