960 likes | 1.26k Views
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
E N D
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” *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 entitymodel_nameis port ( list of inputs and outputs ); endmodel_name; architecturearch_nameofmodel_nameis begin ..... VHDL concurrent statements ..... end arch_name;
when -else library IEEE; use IEEE.std_logic_1164.all; entity mux2to1 is port ( signal s :in std_logic; signal x0,x1 :in std_logic_vector(7 downto 0); signal y :out std_logic_vector(7 downto 0) --brak średnika!!! ); end mux2to1; architecture a1 of mux2to1 is begin y <= x1 when (s=‘1’) else x0; end a1; ALTERA -nazwa pliku musi pokrywać się z nazwą entity (tutaj mux2to1.vhd)
* 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 :out std_logic_vector(7 downto 0); signal b : in std_logic_vector(3 downto 0); możliwe jest przypisanie a <= “100” & b & ‘1’; * ogólna postać warunkowego przypisania sygnału: signal_name <=value1when condition1 elsevalue2 whencondition2 .... elsevalueN when conditionN elsedefault_value; warunki są wyrażeniami przyjmującymi wartości true/false * wynik syntezy:
Przypisanie selektywne (selected signal assignment) * Ogólna postać: withconditionselect signal_name<= value1 whencond_value1, value2whencond_value2, .... valueNwhencond_valueN, valueXwhen others; * warunki mogą być rozdzielone operatorem “or” w postaci | * przykład zastosowania: with sel select a<= d when “000” | “001”, e when “101”, ‘Z’ when others; * w niektórych przypadkach efekt działania identyczny z warunkowym przypisaniem sygnału * współbieżne przypisanie sygnału (concurrent signal assignment), warunkowe (conditional..) i selektywne (selected ...) są instrukcjami współbieżnymi, wykonywanymi jednocześnie i kolejność ich umieszczenia w bloku “architecture” nie ma znaczenia
Multiplekser 2/1 -metoda równań kombinacyjnych library IEEE; use IEEE.std_logic_1164.all; entity mux2to1 is port ( s :in std_logic; x0,x1 :in std_logic_vector(7 downto 0); y :out std_logic_vector(7 downto 0) ); end mux2to1; architecture a2 of mux2to1 is signal temp: std_logic_vector(7 downto 0); begin temp<=(others=>s); y<=(temp and x1) or (not temp and x0); end a2;
* sygnał s (port wejściowy) nie może być bezpośrednio użyty w operacjach logicznych z sygnałami x0 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 temp jest zgodny z x0 i x1 (ta sama szerokość wektora!!!) * każdemu bitowi wektora temp przypisano stan portu wejściowego s temp <= (others=>s); --najprostszy zapis (aggregate) temp<= (s,s,s,others=>s); temp<= (4=>s, 7=>s, 2=>s, 5=>s, 3=>s, 1=>s, 6=>s, 0=>s); temp<= s & s & s & s & s & s & s & s; temp(0)<=s; temp(1)<=s; ..... temp(7)<=s; temp(7 downto 4)<= (s,s,s,s); temp(2 downto 0)<= (others=>s); temp(3)<=s;
* zapis: y<=(temp and x1) or (not temp and x0); jest równoważny z przypisaniem odpowiedniego wyrażenia każdemu elementowi wektora y y(7)<= (temp(7) and x1(7)) or (not temp(7) and x0(7)); y(6)<= (temp(6) and x1(6)) or (not temp(6) and x0(6)); ..... y(0)<= (temp(0) and x1(0)) or (not temp(0) and x0(0)); * ponieważ każdy element wektora temp jest równy s, to wykonywane jest działanie: y(7)<= (s and x1(7)) or (not s and x0(7)); ......
Multiplekser 2/1 -użycie procesu kombinacyjnego/niezegarowanego architecture a3 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 a3; * 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: czas a b c out1 out2 out3 process(a,b,c,out1,out2) t1 0 1 1 0 1 1 begin t2 1 1 1 0->1 1 1 out1<=a and b; t2+d 1 1 1 1 1->0 1->0 out2<=out1 xor c; t2+2d 1 1 1 1 0 0->1 out3<=out1 xor out2; t2+3d 1 1 1 1 0 1 end process * wniosek: pomimo że proces jest kodem sekwencyjnym, to kolejność umieszczenia przypisań do sygnałów jest dowolna
* w procesach których zamierzonym efektem ma być logika kombinacyjna konieczne jest zdefiniowanie sygnałów wyjściowych procesu dla wszystkich możliwych kombinacji wartości sygnałów wejściowych * często, aby uniknąć pomyłki na początku kodu procesu umieszcza się przypisanie wartości domyślnej comb: process(s, x0, x1) begin y<=x0; if (s=‘1’) then y<=x1; end if; end process comb; * w przypadku braku zdefiniowanego wyjścia dla pewnej grupy wartości wejściowych generowane są w procesie syntezy przerzutniki typu latch * proces opisuje reakcje części układu na pobudzenia (sygnały) bez wskazania sposobu realizacji
Enkoder priorytetowy entity en_prior is port( x :in std_logic_vector(1 to 7); enc :out std_logic_vector(2 downto 0) ); end en_prior; architecture e1 of en_prior is begin process(x) -- każdy bit wektora x na liście czułości begin if (x(7)=‘1’) then enc<=“111”; elsif (x(6)=‘1’) then enc<=“110”; elsif (x(5)=‘1’) then enc<=“101”; elsif (x(4)=‘1’) then enc<=“100”; elsif (x(3)=‘1’) then enc<=“011”; elsif (x(2)=‘1’) then enc<=“010”; elsif (x(1)=‘1’) then enc<=“001”; else enc<=“000”; -- domyślna wartość wyjściowa end if; end process; end e1;
enc(2) enc(0) enc(1) x(6) x(4) x(5) x(7) x(2) x(1) x(3) * proces -kod sekwencyjny prowadzi do relizacji układowej czysto kombinacyjnej * kolejność sprawdzania warunków w łańcuchu wyrażeń if-elsif.... definiuje priorytet: najwyższy ma bit 7-my wektora x., bo jego warunek sprawdzany jest w procesie jako pierwszy
* w ramach procesu brane jest pod uwagę wyłącznie ostatnie napotkane podczas analizy kodu przypisanie wartości do sygnału; poniższy proces opisuje ten sam układ: process(x) begin enc<=“000”; --wartość domyślna if (x(1)=‘1’) then enc<=“001”; end if; if (x(2)=‘1’) then enc<=“010”; end if; if (x(3)=‘1’) then enc<=“011”; end if; if (x(4)=‘1’) then enc<=“100”; end if; if (x(5)=‘1’) then enc<=“101”; end if; if (x(6)=‘1’) then enc<=“110”; end if; if (x(7)=‘1’) then enc<=“111”; end if; end process; * bit 7-my ma najwyższy priorytet bo jest testowany jako ostatni (!!!) * ten sam efekt - przypisanie warunkowe, bez użycia procesu: enc <= “111” when x(7)=‘1’ else “110” when x(6)=‘1’ else “101” when x(5)=‘1’ else .... “001” when x(1)=‘1’ else “000”; --wartość domyślna
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( x :in std_logic_vector(1 to 7); enc :out std_logic_vector(2 downto 0) ); end en_prior; architecture eloop of en_prior is begin process(x) variable i: integer; --definicja zmiennej begin i:=7; --przypisanie wartości do zmiennej while (i>0 and x(i)/=‘1’) loop i:=i-1; end loop; enc<=conv_std_logic_vector(i,3); --na drugim miejscu podana liczba pozycji end process; --wektora wynikowego end eloop;
* 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) czas a b c out1 out2 out3 variable out1,out2:std_logic; t1 0 1 1 0 1 1 begin t2 1 1 1 1 0 1->0 out1:=a and b; t2+d 1 1 1 1 0 0 out2:=out1 xor c; t3 1 0 0 0 0 0 out3<=(not out1) and out2; t4 1 0 1 0 1 0->1 end process; t4+d 1 0 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 * UWAGA: konstrukcje z pętlą while są często niesyntezowalne (Altera-Max+PlusII) Synplicity-wynik syntezy jest identyczny jak dla poprzednich architektur
Przykład pętli w układzie kombinacyjnym -opis syntezowalny ENTITY proc IS PORT( d : IN BIT_VECTOR (2 DOWNTO 0); q : OUT INTEGER RANGE 0 TO 3 ); END proc; ARCHITECTURE maxpld OF proc IS BEGIN PROCESS (d) --zliczanie jedynek logicznych w słowie wejściowym VARIABLE num_bits : INTEGER; BEGIN num_bits := 0; FOR i IN d'RANGE LOOP --atrybut RANGE, zmienna i zdefiniow. automatycznie IF d(i) = '1' THEN num_bits := num_bits + 1; END IF; END LOOP; q <= num_bits; END PROCESS; END maxpld;
* użyto wbudowanego typu bit * typ integer jest w układach cyfrowych interpretowany jako słowo binarne; może być wprost użyty w definicji portu bez potrzeby konwersji typu * długość słowa zależy od zakresu liczby integer - w przykładzie 2 bity * standardowo liczba integer zapisywana jest na 32 bitach * wskazówka: w kodzie przeznaczonym do syntezy należy używać jak najmniejszych liczb integer i zawsze ograniczać zakres
* typy pętli: prosta z określonym schematem iteracji L1:loop L2:for I in 1 to 3 loop do_something; A(I)<=B(I); end loop L1; end loop L2; L3:while condition loop do_something; end loop L3; * instrukcje używane w połączeniu z pętlami: 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
GENERATOR PARZYSTOŚCI entity parity is generic (bus_size : integer := 8 ); port ( input_bus : in std_logic_vector (bus_size-1 downto 0); even_numbits, odd_numbits : out std_logic ) ; end parity ; architecture behave of parity is begin process (input_bus) variable temp: std_logic; begin temp := '0'; for i in input_bus'low to input_bus'high loop temp := temp xor input_bus( i ) ; end loop ; odd_numbits <= temp ; even_numbits <= not temp; end process; end behave;
* użyto parametru ogólnego generic; pozwala on na parametryzowanie podprojektów * statyczny (!) przepływ informacji pomiędzy modułami * w szczególności zaleca się używanie tego typu stałej w definiowaniu wymiarów magistral, tablic, parametrów czasowych (w kodzie przeznaczonym do symulacji) * wartość parametru generic może być ustalona przy korzystaniu z danego komponentu na wyższym stopiniu hierarchii, łatwa rekonfigurowalność projektu KOMPARATOR entity compare is generic (size : integer := 16 ); port ( a,b :in std_logic_vector(size-1 downto 0); equal :out std_logic ); end compare; architecture c1 of compare is begin equal<= ‘1’ when a=b else ‘0’; end c1;
Dekoder 3 na 8 entity dec3to8 is port( sel :in std_logic_vector(2 downto 0); --wejścia ena :in std_logic; --output enable y :out std_logic_vector(7 downto 0) --wyjścia aktywne stanem niskim ); end dec3to8; architecture d1 of dec3to8 is begin procd:process(sel,ena) begin y<=“1111_1111”; --wartość domyślna if (ena=‘1’) then case sel is when “000”=> y(0)<=‘0’; when “001”=> y(1)<=‘0’; when “010”=> y(2)<=‘0’; when “011”=> y(3)<=‘0’; when “100”=> y(4)<=‘0’; when “101”=> y(5)<=‘0’; when “110”=> y(6)<=‘0’; when “111”=> y(7)<=‘0’; end case; end if; end process procd; end d1;
* 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;
* wersja dekodera z pętlą w procesie process(sel,ena) begin y<=“1111_1111”; for i in y’range loop if (ena=‘1’ and i=conv_integer(sel)) then y(i)<=‘0’; end if; end loop; end process; funkcja konwersji conv_integer jest dostępna po zadeklarowaniu use ieee.std_logic_unsigned.all; * wersja może być łatwo sparametryzowana (z użyciem generic), przypisanie wartości domyślnej należy wówczas zastąpić drugą pętla: for j in y’range loop y(j)<=‘1’; end loop;
Operatory przesunięcia (shift) sll, srl, sla, sra, rol, ror -lewym argumentem jest bit_vector, prawym liczba całkowita sll, srl uzupełniają wektor wartością ‘0’ sla, sra powielają ostatni bit rol, ror wykonują rotację Uwaga: modelując rejestry przesuwne używa się operatora podstawienia z przesunięciem indeksów w wektorach i operatora sklejania &, zamiast operatorów przesunięcia * wersja dekodera 3 na 8 z operatorem przesunięcia architecture shift1 of dec3to8 is begin with ena select y<= to_stdlogicvector(“1111_1110” rol conv_integer(sel)) when ‘1’, “1111_1111” when others; end shift1;
Pół-sumator i pełny sumator 1 bitowy entity halfadder is port( a,b :in std_logic; sum,cout :out std_logic); end halfadder; architecture a1 of halfadder is begin process(a,b) --OPIS BEHAWIORALNY begin if (a=‘1’ and b=‘1’) then cout<=‘1’; else cout<=‘0’; --cout<=a and b; end if; if ((a=‘1’ and b=‘0’) or (a=‘0’ and b=‘1’)) then sum<=‘1’; else sum<=‘0’; --sum<=a xor b; end if; end process; end a1;
HALFADDER RTL -proces “Technology View”-Flex8000 RTL -równania logiczne
entity fulladder is port( a,b,cin :in std_logic; sum,cout :out std_logic); end fulladder; architecture a1 of fulladder is -- OPIS DATAFLOW (poziom bramek) begin sum<=a xor b xor cin; cout<=(a and b) or (a and cin) or (b and cin); -- or (a and b and cin) end a1;
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( a,b :in std_logic_vector(size-1 downto 0); sum :out std_logic_vector(size-1 downto 0); cin : in std_logic; cout :out std_logic); end fulladder_n; architecture a1 of fulladder_n is signal c :std_logic_vector(size downto 0); begin c(0)<=cin; G: for i in 0 to size-1 generate sum(i)<=a(i) xor b(i) xor c(i); c(i+1)<=(a(i) and b(i)) or (a(i) and c(i)) or (b(i) and c(i)); end generate; cout<=c(size); end a1; * parametr generacji nie musi być deklarowany (tutaj i)
entity adder_n is generic (size : integer := 4 ); port( a,b :in std_logic_vector(size-1 downto 0); sum :out std_logic_vector(size-1 downto 0); cout :out std_logic); end adder_n; architecture a1 of adder_n is signal c :std_logic_vector(size downto 1); begin G1: for i in 0 to size-1 generate G2:if i=0 generate sum(i)<=a(i) xor b(i); c(i+1)<=a(i) and b(i); end generate; --gałęzie else i elsif nie są dozwolone!!! G3: if i>0 generate sum(i)<=a(i) xor b(i) xor c(i); c(i+1)<=(a(i) and b(i)) or (a(i) and c(i)) or (b(i) and c(i)); end generate; end generate; cout<=c(size); end a1;
* ten sam efekt uzyskuje się stosując pętle w procesie architecture a2 of fulladder_n is begin process(a,b,cin) variable c: std_logic; begin c:=cin; L: for i in 0 to size-1 loop sum(i)<=a(i) xor b(i) xor c; c:=(a(i) and b(i)) or (a(i) and c) or (b(i) and c); end loop L; cout<=c; end process; end a2; * istotna jest kolejność przypisań w pętli (c jest zmienną!!!) do obliczenia bieżącej wartości sum(i), oraz przeniesienia c brane jest pod uwagę przeniesienie z poprzedniej pozycji (c wyliczone w poprzednim wykonaniu pętli)
architecture a2 of adder_n is begin process(a,b) variable c: std_logic; begin L: for i in 0 to size-1 loop if i=0 then sum(i)<=a(i) xor b(i); c:=a(i) and b(i); else sum(i)<=a(i) xor b(i) xor c; c:=(a(i) and b(i)) or (a(i) and c) or (b(i) and c); end if; end loop L; cout<=c; c:=‘0’; end process; L: for i in 0 to size-1 loop end a2; sum(i)<=a(i) xor b(i) xor c; c:=(a(i) and b(i)) or (a(i) and c) or (b(i) and c); end loop L; cout<=c;
* wykorzystanie sumowania arytmetycznego zdefiniowanego w pakiecie std_logic_unsigned: architecture a3 of adder_n is signal c :std_logic_vector(size downto 0); begin c<=(‘0’&a)+(‘0’&b); --przy zapisie c<=a+b; sum<=c(size-1 downto 0); --różna szerokość wektora, nie ma gwarancji cout<=c(size); --prawidłowej syntezy !!! end a3; * operacja na liczbach całkowitych: entity fulladder_int is port( a,b :in integer range 0 to 255; sum :out integer range 0 to 511; cin : in integer range 0 to 1); end fulladder_int; architecture a1 of fulladder_int is begin sum<=a+b+cin; end a1;
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 entity adder_4 is port( a,b :in std_logic_vector(3 downto 0); cin :in std_logic; sum :out std_logic_vector(3 downto 0); cout :out std_logic); end adder_4; architecture struct of adder_4 is begin component fulladder port( fa0: fulladder port map(a(0),b(0),cin,sum(0),c0); a,b,cin :in std_logic; fa1: fulladder port map(a(1),b(1),c0,sum(1),c1); sum,cout :out std_logic); fa2: fulladder port map(a(2),b(2),c1,sum(2),c2); end component; fa3: fulladder port map(a(3),b(3),c2,sum(3),cout); signal c0,c1,c2: std_logic; end struct;
* 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( a:in std_logic_vector(size-1 downto 0); 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); -w konfiguracji
Układy sekwencyjne Przerzutniki typu zatrzask (latch) aktywne poziomem * zatrzask jest elementem pamiętającym latch: process(enable,data) process(enable,data) begin begin if (enable=‘1’) then if (enable=‘1’) then q<=data; q<=data; end if; else end process latch; q<=‘0’; end if; end process; -- q<=enable and data; enable data q
* na liście czułości procesu należy umieścić wejście zegarowe oraz wejście danych(!) * układ jest transparentny jeżeli warunek enable=‘1’ jest spełniony; w przeciwnym wypadku proces nie zawiera żadnych instrukcji -na wyjściu q pamiętana jest ostatnia wartość wejścia data przy aktywnym zegarze * proces z określonym sterownikiem dla warunku enable/=‘1’ będzie syntezowany jako bramka AND * w technologiach w których przerzutniki typu latch nie są dostępne, synteza prowadzi do ekwiwalentu złożonego z bramek objętych sprzężeniem zwrotnym * zatrzaski mogą być również generowane poza procesem w części współbieżnej b1: block (enable=‘1’) --warunek dozorujący bloku begin q<= GUARDED data; --sygnał dozorowany end block;