» 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
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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'.
|
|
|
|
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'.
|
|
|
|
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ć:
|
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 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:
nie zmienić stanu na wyjściach Q i nieQ, jeśli R = S = '0',
przyjąć na wyjściu Q stan '0' i na wyjściu nieQ stan '1', jeśli R = '1' i S = '0',
przyjąć na wyjściu Q stan '1' i na wyjściu nieQ stan '0', jeśli R = '0' i S = '1'.
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'.
|
|
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.
|
|
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).
|
|
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ą.
|
|
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:
|
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 asynchroniczny modulo 2
|
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
|
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
|
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
Ci = 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
Vi = 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:
|
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;