Útržky z jazyka VHDL
Jako student fakulty informačních technologií často řeším nejrůznější projekty. Zpočátku jsem myslel, že mi projekt do předmětu Návrh počítačových systémů dá zabrat, protože to není zrovna moje parketa a jazyk VHDL jsem dosud moc neovládal, ale nakonec jsem byl příjemně překvapen a měl jsem z projektu dobrý pocit.
Nebudu se ovšem zmiňovat o proprietálním software, který je potřeba k programování ve VHDL. Program ModelSim a knihovny od společnosti Xilinx se mi na Linuxu nepodařily propojit a VHDL jsem kompiloval u kolegy. Z tohoto hlediska jsem zklamán, neboť už jenom dostat k požadovanému software licence může být heroický úkol (pro mě). Tím se zabývat nebudu. Místo toho představím 4 hardwarové komponenty v jazyce VHDL. Jinak řečeno vytrhnu čtyři součástky z projektu návrhu jednoduché střadačové architektury, ukážu jejich kód a malinko jej okomentuju.
Jednoduchou střadačovou architekturou zadavatel myslel třemi instrukcemi ovládanou poloviční sčítačku, která příjímá operandy z paměti a ze střadače a výsledek ukládá zpět do střadače. Jako ovládací prvek je použit konečný automat. Ten jako jediný vynechám a představím jen RAM, multiplexor, střadač a sčítačku. Všechno uvedu jako jednotlivé procesy v činnosti jednoduché střadačové architektury. Komponenty jsou propojeny signály (dráty), které budu definovat na přeskáčku, ale mělo by jít poznat, co k čemu patří.
Sčítačka
Požadovaná sčítačka je ve VHDL zapsána velice jednoduše, ale s tím přichází i její omezení. Jelikož jsou vstupy i výstup 8-bitové a sčítačka neošetřuje přetečení, musí být hodnoty obou vstupů menší než 128. V reálné praxi by se to jistě muselo ošetřit, ale zadavatel řekl neošetřovat, takže stačí použít operátor "+" jazyka VHDL a celý proces vypadá následovně.
scitacka: process(add_in1, add_in2) begin add_out <= add_in1 + add_in2; end process;
A signály, které jsou použity, jsou definovány jako 8-bitové.
signal add_in1, add_in2, add_out : std_logic_vector(7 downto 0);
Čekal jsem, že to bude horší, ale sčítačka ve VHDL je opravdu jednoduchá.
Střadač
Další součástkou je registr, který uchovává svou datovou hodnotu, dokud mu neřekneme, aby uchovával jinou. Dráty na vstupu i na výstupu jsou 8-bitové a součástka je řízena třemi drátky: CLK (hodinový signál), RESET (signál pro vynulování) a WRITE (signál povolující zápis).
signal add_in, add_out : std_logic_vector(7 downto 0); signal WRITE, CLK, RESET : std_logic; stradac: process(RESET, CLK) begin if (RESET = '1') then -- vynulování acc_out <= (others => '0'); elsif (CLK'event) and (CLK = '1') then -- zápis s náběžnou hranou if (WRITE = '1') then acc_out <= acc_in; -- jednoduše uděláme ze vstupu výstup end if; end if; end process;
VHDL není zas tak hrozný jazyk, jak se může zdát. Selekce pomocí if-else je velmi podobná vyšším programovacím jazykům, stejně jako je ukládání hodnot signálů podobné definicím proměnných.
Multiplexor
Součástka, která má jako vstup několik signálů a my vybereme jeden jako její výstup, se dá ve VHDL zapsat několika způsoby. Já jsem multiplexor implementoval jako další samostatný proces. Ze dvou 8-bitových vstupů dat vybereme jeden na výstup pomocí 1-bitového signálu SELECT.
signal in1, in2, mux_out : std_logic_vector(7 downto 0); signal SELECT : std_logic; multiplexor: process(in1, in2, SELECT) begin case SELECT is when '0' => mux_out <= in1; when '1' => mux_out <= in2; when others => mux_out <= "ZZZZZZZZ"; -- stav vysoké impedance end case; end process;
Objevuje se zde další konstrukce jazyka VHDL, kterou všichni známe z vyšších programovacích jazyků. Konstrukci konečného automatu v jazyce C bychom zapsali pomocí klíčových slov switch a case. Ta jsou zde nahrazena za case a when, ale význam mají stejný.
Upozorňuji, že ve VHDL musí být uvedeno when others, jinak bude kompilátor hlásit chybu.
RAM
Poslední komponentou je paměť. V tomto případě se jedná o RAM složenou ze čtyř 8-bitových hodnot, tedy paměť adresovatelnou dvěma bity - 2-bitovým signálem. Vstup i výstup mají stejný počet bitů jako jedna paměťová buňka a vše je řízeno čtyřmi signály. Se signály CLK a RESET jsme se setkali u střadače, avšak narozdíl od něj potřebujeme kromě zápisu řídit i čtení, a proto je zde kromě signálu WRITE i signál READ. Jsou-li READ a WRITE oba v nule, nic se neděje. Naopak předpokládáme, že WRITE i READ nebudou mít současně hodnotu 1. Jinak aktivní WRITE značí, že se do paměti zapisuje vstup a aktivní READ značí čtení z paměti na výstup.
type mem_array is array(0 to 3) of std_logic_vector(7 downto 0); signal mem : mem_array; signal READ, WRITE : std_logic; signal address : std_logic_vector(1 downto 0); signal mem_in, mem_out : std_logic_vector(7 downto 0); ram: process(RESET, CLK) begin if (RESET = '1') then -- stav vynulování mem_out <= "ZZZZZZZZ"; -- vysoká impedance na výstupu mem(0) <= X"50"; -- libovolné hodnoty v paměti mem(1) <= X"4E"; -- X před uvozovkami vyjadřuje mem(2) <= X"00"; -- hexadecimální hodnotu mem(3) <= X"00"; elsif (CLK'event) and (CLK =' 1') then if (READ = '1') then mem_out <= mem(conv_integer(address)); -- výstup z RAM elsif (WRITE = '1') then mem(conv_integer(address)) <= mem_in; -- vstup do RAM mem_out <= "ZZZZZZZZ"; -- výstup je vysoká impedance else -- nedefinovany stav mem_out <= "ZZZZZZZZ"; end if; end if; end process;
Za povšimnutí zde stojí vytváření pole signálů (úplně nahoře) a jeho použití (při stavu RESET). Dále je zde použita funkce conv_integer. Jinak se opět jedná o selekci a přiřazování signálů do signálů.
Co z toho plyne?
Programování v jazyce VHDL není težké a je velmi podobné vyšším programovacích jazykům, od kterých se liší hlavně klíčovými slovy a tím, že nepracujeme s abstraktními proměnnými, ale s defacto fyzickými věcmi typu drát nebo hradlo, které vedou odněkud někam a které jsou jen pojmenovány jako proměnné. Aspoň tak mi to příjde po víceméně první práci s tímto zajímavým jazykem. Nebojte se jazyka VHDL!