Funkce, procedury, balíčky

Ano, zase se posuneme od drátů k trošku vyšším abstrakcím.

Funkce

Možná vás napadlo, že by bylo dobré některé opakované operace v procesech nadefinovat nějak obecněji, tak, aby byly znovupoužitelné, abyste nemuseli psát kód copy-and-paste, což je vždycky cesta do pekel. Kdyby tak VHDL mělo funkce, co? A vidíte, má je!

Seznam parametrů je v závorce a je nepovinný. Na konci je nepovinné klíčové slovo FUNCTION a jméno funkce. Ale doporučuju, jako už několikrát, zvyknout si psát END FUNCTION. Syntax zápisu je podobná jazyku C, a ještě podobnější jazyku Pascal, takže pokud znáte Pascal, nepřekvapí vás nic.

Funkci můžete vytvořit v deklaračním bloku u ARCHITECTURE, ENTITY, nebo PROCESS. Popřípadě i v deklaračním bloku jiné funkce.

Funkce je podobná procesu v tom, že má rovněž deklarační a příkazovou část, a že se příkazy v těle vykonávají sekvenčně. Na rozdíl od procesu má funkce návratovou hodnotu (vždy jednu jedinou!) a volitelné parametry.

Seznam parametrů je podobný deklaracím v bloku ARCHITECTURE – parametry jsou definované jako SIGNAL, nebo jako CONSTANT (VARIABLE není dovoleno), a podle toho se budou ve funkci chovat. Všechny mají typ „IN“, tedy směr dovnitř, do funkce.

Assert

Píšu „volitelné parametry“, takže by bylo dobré je zkontrolovat. Opět připomínám, že, stejně jako proces, se ani funkce „nespouští“ ve FPGA, místo toho syntetizér „zadrátuje“ algoritmus do obvodů, takže je možné udělat některé statické kontroly přímo ve funkci. Například zkontrolovat, jestli mají parametry správné… ehm… parametry (jako že vlastnosti). Slouží k tomu konstrukce ASSERT.

Pokud je podmínka splněna, nestane se nic. Pokud není splněna (=FALSE), jste na to upozorněni. Můžete pomocí „REPORT“ popsat, co se stalo – do hlášení můžete zahrnout i hodnoty proměnných či signálů a spojit je do jednoho řetězce spojovacím operátorem &. Pomocí SEVERITY můžete sdělit závažnost hlášení. NOTE a WARNING nezastaví proces syntézy, ERROR nebo FAILURE jej zastaví.

Řekněme, že funkce dostane dva vektory (A a B) a něco s nimi provede, to teď není podstatné, podstatné je, že je potřeba, aby oba vektory měly stejný počet bitů. Jako první příkaz tedy uvedeme:

Porovnáme tedy délku obou vektorů (pomocí atributu ‚LENGTH), a pokud není stejná, vypisujeme hlášení a zastavujeme syntézu – chyba je natolik závažná, že nelze pokračovat dál.

Pomocí assert můžeme vytvořit i testovací výpisy – ASSERT FALSE REPORT „…“ Pokud chcete do výpisu zahrnout hodnotu nějaké proměnné nebo signálu, můžete, ale musíte ji nejprve převést na řetězec. K tomu slouží atribut ‚IMAGE – ten se neváže ke konkrétní proměnné, ale k typu, a používá se např. takto: INTEGER’IMAGE(hodnota). Některé typy (std_logic_vector) nemají ‚IMAGE, je proto potřeba je nejprve přetypovat na integer.

Volání funkcí

Tady není nic nezvyklého a zapisuje se tak, jak byste čekali:

Procedury

Stejně jako v Pascalu se rozlišují funkce (vrací 1 hodnotu) a procedury (nevrací nic), tak i ve VHDL se rozlišují funkce (vrací 1 hodnotu) a procedury (nevrací nic, ale mohou měnit paramtery). Syntax je podobná funkcím, odpadá RETURN, a seznam hodnot může obsahovat kromě konstant a signálů i proměnné. Navíc mohou být parametry deklarované jako IN, OUT nebo INOUT.

Třeba:

Volání je podobné jako u funkcí, jen se používá samostatně, nikoli ve výrazu (protože nevrací hodnotu).

Přetěžování

VHDL jako silně typovaný jazyk umožňuje velmi snadnou implementaci přetěžování funkcí. Kterou definici použije, to se rozhodne polde typu parametrů. Například balíček numeric_std přetěžuje funkci „+“ (tedy operátor sčítání) rovnou šestkrát:

Příklad, v němž si přetížíme operátor „plus“ pro sčítání „slv“ (std_logic_vector), najdete na konci článku.

Balíčky

Stejně jako má Pascal své Unity a C svoje header soubory (no, zas tak stejné to není…), tak má i VHDL koncept balíčků. Už je používáme – to je to „use ieee.numeric_std.all;“ Čtěte jako „Použij balíček numeric_all z knihovny ieee, a z něj vezmi všechno“. Zjednodušuje to a usnadňuje znovupoužitelnost některých konstrukcí (funkcí, procedur, vlastních typů atd.)

Balíček (Package) se skládá ze dvou částí, z deklarace obsahu (Package) az vlastních definic (Package body).

Package body je nepovinné, a pokud balíček obsahuje např. jen deklarace typů, je zbytečné.

V části Package jsou uvedeny pouze deklarace. Tedy deklarace typů, konstant, signálů, aliasů, funkcí, procedur a dalších věcí, na které ještě přijde řeč. Pokud deklarujeme funkci či proceduru, tak podobně jako v C uvedeme pouze její hlavičku (tj. část až do klíčového slova IS) a ukončíme středníkem:

V této deklaraci se říká, že balíček obsahuje typ matrix, jeden signál jménem „pole“ s typem matrix, celočíselnou konstantu max s hodnotou 255 a funkci getbit, která břijímá dva dvoubitové signály a vrací jednobitovou hodnotu.

Vlastní definice chování funkce getbit je uvedena až v části Package body. Zde je uvedena kompletní definice funkce, jak jsme si ukázali výš.

Konstanty mohou být „odložené“, to znamená, že jsou v Package pouze deklarované (CONSTANT max:integer;) a hodnota jim je přiřazena až v Package body (CONSTANT max: integer:=255;)

Balíček použijeme pomocí klíčového slova „use“. Pokud je definovaný v rámci aktuálního projektu, bude mít jeho použití tvar „use work.muj_balicek.all;“  Aktuální projekt vždy odpovídá knihovně „work“.

A zde je slíbená ukázka: Balíček „muj_balicek“, který obsahuje funkci „+“, přetíženou pro dva vektory o stejné velikosti. K tomu i dva užitečné atributy, které jsem zatím nezmínil, totiž ‚RANGE a ‚REVERSE_RANGE. Oba udávají rozsah vektoru, jeden tak, jak byl vektor definován, druhý v obráceném pořadí.

Příklad: Vektor je a: std_logic_vector (7 downto 0). Pak a’RANGE odpovídá (7 downto 0), a’REVERSE_RANGE je (0 to 7).

Upozornění: Funkce nefunguje při sčítání vektoru a literálu, pro takové použití by bylo potřeba ji upravit a obě vstupní hodnoty nejprve převést na stejný typ. Neřeší ani rozdílné délky vstupních vektorů. První problém vyřeší například alias, což je způsob, jak si „přetypovat“ signál pod jiným jménem:

Úpravu, ve které správně vezmete velikost výsledku jako „větší z velikostí a, b“ a tomu odpovídajícím způsobem ošetříte vlastní sčítání, nechám na vás.