Typy, operátory a atributy

Nadešel čas… Ale nebojte, bude to krátké, výživné, a velmi užitečné.

I ve VHDL máme možnost zapisovat aritmetické operace. Minule jsem ukazoval základní číselné typy, vysvětlil, proč používat numeric_std a naznačil, že s nimi lze dělat nějaká ta matika. Pojďme na to!

Základní typy ve VHDL

Každý jazyk má nějaké základní typy, s nimiž se dál pracuje. Ve VHDL jich je rovnou několik – nebudu se rozepisovat podrobněji, spíš jen tak shrnu:

Typ Hodnoty Knihovna
std_ulogic (sul) ‚U‘, ‚X‘, ‚0‘, ‚1‘, ‚Z‘, ‚W‘, ‚L‘, ‚H‘, ‚-‚ std_logic_1164
std_ulogic_vector (sulv) Vektor (pole) hodnot typu std_ulogic std_logic_1164
std_logic (sl) jako std_ulogic, resolved (tj. rozhodnuté hodnoty) std_logic_1164
std_logic_vector (slv) Vektor hodnot typu std_logic std_logic_1164
unsigned (uv) SLV N bitů, rozsah 0 .. 2N-1 numeric_std
signed (sv) SLV N bitů, rozsah -2N-1 .. 2N-1-1 numeric_std
boolean výčet (true, false) standard
character znak ASCII standard
string pole znaků standard
integer 32bitové signed číslo (-231 – 1 .. 231 – 1) standard
 real -1.0E38 .. 1.0E38 standard
 time 1 fs .. 1 hr (femtosekunda až hodina) standard

Unsigned, signed čísla jsou i v knihovnách std_logic_arith, std_logic_unsigned nebo std_logic_signed. Neměli byste je používat (jsou deprecated a nejsou standard IEEE), ale měli byste o nich vědět (byly dlouho „de facto průmyslový standard“). Podobný případ jsou typy bitbit_vector, které byly nahrazeny std_logic.

K typům jako boolean, integer apod. existují i jejich vektorové podoby. K typu integer existují i subtypy natural (přirozená čísla s nulou, tj. nezáporná) a positive (celá kladná čísla).

Konverze

Ve VHDL jsou některé typy převedeny na jiné automatickou konverzí, jiné musíme převádět explicitní konverzí. Mezi ty implicitní patří:

  • Konverze mezi std_logic a std_ulogic je automatická
  • Elementy vektorů „signed“, „unsigned“ a „std_logic_vector“ jsou automaticky převáděny na skalární hodnoty std_logic, std_ulogic

Explicitní konverze mezi signed, unsigned a vektory používá název typu a závorky:

  • slv <= std_logic_vector(uv);
  • slv <= std_logic_vector(sv);
  • uv <= unsigned(slv);
  • sv <= signed (slv);

Explicitní konverze mezi signed, unsigned a integer používá funkce to_xxx:

  • int <= to_integer (uv);
  • uv <= to_unsigned (int, 8);
  • sv <= to_signed (int, 8);

Funkce to_unsigned, to_signed vyžadují druhý parametr, který udává velikost výsledného vektoru v bitech.

Konverze mezi vektorem a integerem vyžaduje mezikrok přes unsigned nebo signed.

Někdy není jasné, jak vyhodnotit literál. Například ve výrazu sv + „1010“ není jasné, jestli k signed vektoru přičítáme hodnotu 10, nebo -6.

Uživatelské typy

VHDL umožňuje definovat vlastní typy dat, podobně jako Pascal. Používá se klíčové slovo type, zápis je „type {jméno typu} is {popis typu}“.

Celočíselné typy

Pomocí klíčového slova „range“ určíme rozsah celočíselného typu. Rozsah se musí vejít do rozsahu typu integer (32 bitů). Například

Pokud použijete jen typ „integer“, VHDL si pro něj vyhradí 32 bitů, což bude většinou nehorázné plýtvání. Proto tam, kde to má smysl, omezte rozsaho pomocí nějaké výše uvedené definice.

Výčty

Obdoba typu množina v Pascalu, popř. enum z C. V závorkách je uveden výčet možných hodnot:

Pole

Pole je, jako v jiných jazycích, struktura obsahující elementy stejného typu. Zápis je „type {jméno typu} is array ({specifikace rozsahu}) of {typ elementů}“.

Specifikace rozsahu je buď přímo zapsaný rozsah (např. „0 to 3“), nebo specifikace toho, jakých hodnot může nabývat. „Natural range <>“ znamená, že je očekávaný rozsah v rámci přirozených čísel. Specifikace může obsahovat víc položek oddělených čárkou, pak vznikne vícerozměrné pole. Jako specifikace může být použit i výčet…

Záznamy

Ano, Pascal opět vystrkuje růžky. Záznam (record) je kompozitní typ, který umožňuje do jednoho typu spojit víc různých typů.

Například:

Na položky se odkazujeme dobře známou tečkovou notací.

Konstanty

Zapráskat si kód „magickými konstantami“ dokáže každá lama. Člověk s nějakou sebeúctou použije pojmenovanou konstantu.

Za slovem constant je jméno konstanty, za dvojtečkou její typ, a za znakem „:=“ hodnota.

Operátory

VHDL nabízí standardní sadu matematických a logických operátorů, jaké jsou běžné i v jiných jazycích. Z toho, co jsem psal výš, je jasné, že jejich použití nebude žádná selanka a že budou muset existovat jasná pravidla pro to, co se stane, když se potkají v jednom výrazu hodnoty různých typů. A protože je VHDL silně typovaný, jsou pro něj dva různě definované typy odlišné, i když třeba oba představují osmibitový vektor.

Operátory
Exponent, absolutní hodnota **, abs
Logické and, or, nand, nor, xor, xnor, not
Multiplikativní *, /, mod, rem
Aditivní, negace +, –
Spojování, posuny, rotace &, sll, srl, sla, sra, rol, ror
Relační =, /=, <, <=, >, >=

VHDL základní operátory intenzivně přetěžuje, díky čemuž můžeme například přičítat celá čísla k vektorům (a výsledkem je zase vektor). Pokud máme např. signál „count“, definovaný jako unsigned (uv), můžeme napsat „count + 1″… Platí ale některá pravidla:

  • unsigned + unsigned = unsigned
  • unsigned + integer = unsigned
  • integer + unsigned = unsigned
  • signed + signed = signed
  • signed + integer = signed
  • integer + signed = signed

Navíc platí, že „velikost cíle“ (=počet bitů) musí odpovídat „velikosti výrazu“. Nelze tedy přiřadit výsledek součtu dvou čtyřbitových vektorů do pětibitového (i když by to dávalo smysl). Pokud přemýšlíte, jak velké jsou které výrazy, tak vězte:

Výraz Velikost v bitech
„11001010“ Počet číslic v literálu (8)
X“5A“ Počet znaků * 4
A Velikost vektoru A
A and B Velikost vektorů A a B
A > B Boolean
A + B Velikost většího z vektorů A, B
A + 10 Velikost vektoru A
A * B Velikost A + velikost B

Aditivní operátory (+, -) dávají výsledek o stejné šířce, jako má větší z operátorů. Pokud dojde k přetečení, nejvyšší bit se ztratí.

U relačních operátorů je výsledkem vždy typ boolean. Ačkoli to svádí k záměně se std_logic, není to tak a tyto typy nejsou zaměnitelné.

Bitové operátory představují jednak posuny a rotace, jednak operátor spojení &. Ten použijeme při skládání kratších vektorů do delšího, např. výše zmíněný problém „převést čtyřbitové unsigned číslo na pětibitové“ můžeme vyřešit jako ‚0‘ & A. Dva čtyřbitové vektory složíme do osmibitového pomocí A & B. Podle konvence se skládají hodnoty tak, jak jsou zapsány za sebou, MSB je vlevo.

K těmto operátorům bych zařadil i operátor „výběru rozsahu“. Například – potřebujeme do osmibitového vektoru D zkopírovat horních 8 bitů šestnáctibitového vektoru A: D <= A (15 downto 8). Rozsah vybereme jeho uvedením v závorce za signálem.

Že se vracím ještě k té sčítačce:

Anebo s troškou hackování:

multiplikativních operátorů platí, že pokud opravdu potřebujeme násobit čísla, použijeme násobení, protože ho syntetizér může umístit do hardwarové násobičky (ve FPGA bývají…) Dělení, modulo a operátor zbytku (rem) bývají hůř syntetizovatelné…

Posuny jistě znáte, ale připomenu: Logické (sll, srl) zaplňují volná místa nulami, aritmetické (sla, sra) opakují nejnižší (sla) nebo nejvyšší (sra) bit.

Atributy

Typy ve VHDL definují určité atributy, které jsou použitelné pro zjištění podrobností o typu. Atributy se zapisují jako ‚ATRIBUT, tedy apostrof a jméno atributu, a to přímo za hodnotu nebo typ, na který se ptáme. Ukážeme si je na příkladu:

Svoje atributy mají i signály. Kromě výše uvedených, které se vztahují k typu, lze použít například:

Používá se např. k detekci náběžné hrany hodin v procesech: clk’event and clk=’1′

Atributy pomohou nejen u zpracování signálů, ale např. i při definici generických entit.

Nejen typy, ale i operátory a atributy můžeme definovat vlastní, ale to bych odložil na „až někdy…“

Příště: Proces. Kafku s sebou!