Jak pracować z VHDL przy użyciu bezpłatnego oprogramowania

Klasy inżynieria elektroniczna są zwykle podyktowane za pomocą popularne narzędzia, więc zawsze spędzam kilka godzin, szukając pracy wolne oprogramowanie. Z tego powodu postanowiłem podzielić się poniższymi informacjami przewodnik.

To wkład od pandacris, stając się tym samym jednym ze zwycięzców naszego cotygodniowego konkursu: «Podziel się swoją wiedzą o Linuksie«. Gratulacje!

Instalowanie niezbędnych

Do kompilacji i symulacji naszych programów użyjemy GHDL, darmowego kompilatora opartego na GCC. Aby zobaczyć wyniki symulacji, użyjemy GTKWAVE. Jako redaktor polecam Geany, ponieważ rozpoznaje prawie wszystkie języki programowania.

sudo apt-get zainstaluj ghdl gtkwave geany

Przykładowy projekt

Użyjmy tego komparatora jako przykładu:

Przed utworzeniem projektu zacznijmy od utworzenia folderu, w którym będą hostowane wszystkie pliki. W tym przypadku / home / user / vhdl. Tam zapiszemy kod źródłowy naszych programów z rozszerzeniem .vhd.

Następnie piszemy nasz program przy użyciu Geany, jak widać na zrzucie ekranu.

Zapisujemy go jako compare.vhd.

Nie zapomnij zapisać programu z rozszerzeniem .vhd, aby Geany rozpoznawał format i kolorował zarezerwowane słowa.

Teraz będziemy musieli stworzyć sygnały do ​​symulacji. Aby to zrobić, utworzymy komponent, który używa poprzedniego bloku i określimy sygnały.

Linie A <= „0011” po 0 ns, „0111” po 5 ns, „0111” po 10 ns; to te, które konfigurują sygnały wejściowe w czasie

Zapisujemy pliki w / home / user / vhdl. Następnie otwieramy terminal i kompilujemy:

ghdl -a porównaj.vhd

Jeśli nie ma komunikatów o błędach, kompilacja zakończyła się pomyślnie.

Teraz kompilujemy „komponent”

ghdl -a compare_tb.vhd

Jeśli nie ma błędów, tworzymy plik wykonywalny:

ghdl -e porównaj_tb

Na koniec pozostaje wykonanie symulacji i zapisanie wyników w nazwie „porównaj.vcd”

ghdl -r porównaj_tb --vcd = porównaj.vcd

Aby zobaczyć wyniki, użyjemy gtkwave:

gtkwave compare.vcd

Po otwarciu użyj klawisza Ctrl i myszy, aby wskazać sygnały, które nas interesują, i naciśnij wstaw. Następnie kliknij dwukrotnie wektory, aby zobaczyć oddzielne sygnały. Następnie kliknij prawym przyciskiem myszy sygnały, aby wybrać format (binarny, szesnastkowy, ósemkowy, dziesiętny itp.)

W razie potrzeby przycisk lupy z kwadratem pośrodku dostosowuje wykres do ekranu.

ALU: jednostka arytmetyczno-logiczna

OK, zróbmy teraz coś bardziej interesującego: ALU (jednostka arytmetyczna i logiczna). Będzie to jednostka logiczna, jednostka arytmetyczna i multiplekser.

Dysk logiczny (LoU.vhdl)

     LIBRARY ieee; UŻYJ IEEE.STD_LOGIC_1164.all; UŻYJ IEEE.NUMERIC_STD.all;

ENTITY lou JEST
PORT (op1: IN std_logic_vector (7 DOWNTO 0);
op2: IN std_logic_vector (7 W DÓŁ 0);
proces: IN std_logic_vector (3 W DÓŁ 0);
res: OUT std_logic_vector (7 W DÓŁ 0));
KONIEC lou;

ARCHITEKTURA synth2 OF lou IS
SIGNAL a, b: UNSIGNED (op1'range);
SIGNAL c: UNSIGNED (zmień zakres);
ZACZYNAĆ
PROCES (a, b, proces)
ZACZYNAĆ
CASE proces JEST
KIEDY "0000" => c <= ZMIEŃ ROZMIAR ((nie a), c'length);
KIEDY "0001" => c <= ZMIEŃ ROZMIAR ((a i b), c'length);
KIEDY "0010" => c <= ZMIEŃ ROZMIAR ((a lub b), c'length);

KIEDY "0011" => c <= ZMIEŃ ROZMIAR ((a xor b), c'length);
KIEDY "0100" => c <= ZMIEŃ ROZMIAR ((a nand b), c'length);
KIEDY "0101" => c <= ZMIEŃ ROZMIAR ((a ani b), c'length);
KIEDY INNE => null;
KOŃCÓWKA;
KONIEC PROCESU;

a <= UNSIGNED (op1);
b <= UNSIGNED (op2);
res <= std_logic_vector (c);

KONIEC syntezatora2;

Jednostka arytmetyczna (ArU.vhd)

     LIBRARY ieee; UŻYJ IEEE.STD_LOGIC_1164.all; UŻYJ IEEE.NUMERIC_STD.all;

ENTITY aru JEST
PORT (op1: IN std_logic_vector (7 DOWNTO 0);
op2: IN std_logic_vector (7 W DÓŁ 0);
proces: IN std_logic_vector (3 W DÓŁ 0);
res: OUT std_logic_vector (7 W DÓŁ 0));
KONIEC;

ARCHITEKTURA syntezator aru IS
SIGNAL a, b: UNSIGNED (op1'range);
SIGNAL c: UNSIGNED (zmień zakres);
ZACZYNAĆ
PROCES (a, b, proces)
ZACZYNAĆ
CASE proces JEST
KIEDY "0000" => c <= ZMIEŃ ROZMIAR ((a + b), c'length);
KIEDY "0001" => c <= ZMIEŃ ROZMIAR ((a - b), c'length);
KIEDY "0010" => c <= ZMIEŃ ROZMIAR ((a * b), c'length);

KIEDY "0011" => c <= ZMIEŃ ROZMIAR ((a / b), c'length);
KIEDY "0100" => c <= ZMIEŃ ROZMIAR ((a + "1"), c'length);
KIEDY "0101" => c <= ZMIEŃ ROZMIAR ((b + "1"), c'length);
KIEDY INNE => null;
KOŃCÓWKA;
KONIEC PROCESU;

a <= UNSIGNED (op1);
b <= UNSIGNED (op2);
res <= std_logic_vector (c);

END syntezator;

Multiplekser (muxVector.vhd)

     LIBRARY ieee; UŻYJ IEEE.STD_LOGIC_1164.all; UŻYJ IEEE.NUMERIC_STD.all;

ENT. muxVector JEST
PORT (z ARU: IN std_logic_vector (7 W DÓŁ 0);
fromLOU: IN std_logic_vector (7 DOWNTO 0);
przełącznik: IN std_logic;
wyjście: out std_logic_vector (7 DOWNTO 0));
KONIEC muxVector;

ARCHITEKTURA zmiana muxVector IS
ZACZYNAĆ
za pomocą przełącznika wyboru
wyjście <= z ARU, gdy '0', z LOU, gdy inni;
KONIEC zmiana;

Komponent ALU (aluComponent.vhd)

     LIBRARY ieee; UŻYJ IEEE.STD_LOGIC_1164.all; UŻYJ IEEE.NUMERIC_STD.all;

ENTITY alu Component IS
END aluComponent;

ARCHITEKTURA input_aluComponent OF aluComponent IS

KOMPONENT aru
PORT (op1: IN std_logic_vector (7 DOWNTO 0);
op2: IN std_logic_vector (7 W DÓŁ 0);
proces: IN std_logic_vector (3 W DÓŁ 0);
res: OUT std_logic_vector (7 W DÓŁ 0));
KOMPONENT KOŃCOWY;

KOMPONENT lou
PORT (op1: IN std_logic_vector (7 DOWNTO 0);
op2: IN std_logic_vector (7 W DÓŁ 0);
proces: IN std_logic_vector (3 W DÓŁ 0);
res: OUT std_logic_vector (7 W DÓŁ 0));
KOMPONENT KOŃCOWY;

SKŁADNIK muxVector
PORT (z ARU: IN std_logic_vector (7 W DÓŁ 0);
fromLOU: IN std_logic_vector (7 DOWNTO 0);
przełącznik: IN std_logic;
wyjście: out std_logic_vector (7 DOWNTO 0));
KOMPONENT KOŃCOWY;

SIGNAL outputARU: std_logic_vector (7 DOWNTO 0);
SIGNAL outputLOU: std_logic_vector (7 DOWNTO 0);
Przełącznik sygnału: std_logic;
proces sygnału: std_logic_vector (3 DOWNTO 0);
wyjście sygnału: std_logic_vector (7 DOWNTO 0);
SYGNAŁ A: std_logic_vector (7 W DÓŁ 0);
SIGNAL B: std_logic_vector (7 W DÓŁ 0);

ZACZYNAĆ
u0: aru MAPA PORTU (A, B, proces, wyjście ARU);
u1: lou MAPA PORTU (A, B, proces, wyjście LOU);
u2: muxVector PORT MAP (outputARU, outputLOU, switch, output);

A <= „00000011” po 0 ns, „00000111” po 5 ns, „00000111” po 10 ns, „00001001” po 15 ns, „00000000” po 20 ns, „00000101” po 25 ns, „00001111” po 30 ns ns, „00000101” po 35 ns;
B <= „00000010” po 0 ns, „00000100” po 5 ns, „00000010” po 10 ns, „00000011” po 15 ns, „00000100” po 20 ns, „00000110” po 25 ns, „00001111” po 30 ns ns, „00000011” po 35 ns;
zmiana <= '1' po 0 ns, '0' po 5 ns, '1' po 10 ns, '0' po 15 ns, '1' po 20 ns, '0' po 25 ns, '1' po 30 ns, „0 ′ po 35 ns,„ 1 ′ po 40 ns;
proces <= „0000” po 0 ns, „0001” po 5 ns, „0010” po 10 ns, „0011” po 15 ns, „0100” po 20 ns, „0101” po 25 ns, „0110” po 30 ns;
END input_aluComponent;

Aby nie tracić czasu na kompilowanie polecenia komendą podczas pracy nad programem, w tym samym folderze zapisujemy plik o nazwie compilar.sh z następującą zawartością:

ghdl -a lou.vhd && ghdl -a aru.vhd && ghdl -a muxVector.vhd && ghdl -a aluComponente.vhd && ghdl -e aluComponente && ghdl -r aluComponent --vcd = alu & componente.wave

Otwórz terminal, wejdź do folderu i uruchom skrypt:

cd / home / user / vhdl sh compile.sh

Jeśli nie ma błędów, to gtkwave się otworzy i możemy zobaczyć sygnały:

Narzędzia te były bardzo przydatne i łatwiejsze w użyciu niż zastrzeżone narzędzia, których używamy na zajęciach, których kompilacja jest podejrzanie zbyt długa. W przypadku ghdl przełączanie okien trwa dłużej niż kompilacja.

Więcej informacji o VHDL

Dla nowych użytkowników vhdl, tutaj mają podstawowy przykład deniera.

Przykładowe wideo:
http://www.youtube.com/watch?v=feVMXsyLSOU

Pamiętaj, że najnowsze wersje Ubuntu nie mają GHDL w swoich repozytoriach. Można to pobrać dla systemu Linux / Windows ze strony projektu:
http://ghdl.free.fr/site/pmwiki.php?n=Main.Download