Hello world!

Lžu. Ještě ani zdaleka ne. Křivka učení je hodně povlovná a ještě musíme pár věcí probrat, než si blikneme LEDkou…

V úvodu jsem psal, že VHDL je deklarační a popisný jazyk (nikoli imperativní) a že je na první pohled trochu blízký Pascalu. Pojďme si ukázat základní koncepty.

Naše stavební bloky ve VHDL jsou entity. Entita je popsána jednak svým rozhraním navenek (viz minule zmiňovaný port), jednak svou vnitřní architekturou. Ta může být popsána několika způsoby, opět viz úvod, a v praxi se nejčastěji potkáte s jejich mixem.

Pojďme si nejprve nadefinovat entitu, která bude provozovat neúplné jednobitové sčítání. Jak to funguje?

Při sčítání dvou jednobitových hodnot je pravidlo prosté:

  • 0+0 = 0
  • 1+0 = 1
  • 1+1  = 10 – a protože sčítáme jednobitově, tak je výsledek 0 a nastavený přenos.

Naše entita tedy bude mít dva vstupy, A a B (vstupní přenos neuvažujeme, proto neúplná sčítačka), a dva výstupy, Q a Cout. Můžeme si sepsat pravdivostní tabulku…

A B Q Cout
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

Můžeme s tím ještě laborovat dál, ale u téhle jednoduché funkce na první pohled vidíme, že Q je A XOR B, Cout je A AND B. Můžeme zvolit strukturální zápis, ale tady bude vhodnější zápis stylem data flow.

Rozebereme si to po jednotlivých blocích.

Tyto dva řádky se snad raději naučte nazpaměť jako říkadlo. Znamenají, že budeme používat standardní knihovnu, definovanou organizací IEEE, a z této knihovny využijeme tu část, kde jsou definované standardní pojmy, související s logickými výrazy – jednobitové logické hodnoty, vícebitové vektory apod.

 

Poznámky začínají dvěma znaky „minus“. Cokoli od nich dál je poznámka

Raději hned teď upozorním na jednu věc, která je schopna nadělat spoustu zlé krve: Základním logickým typem je std_ulogic, který používá devítihodnotovou logiku. Definované hodnoty jsou:

Označení Hodnota
‚U‘ Neinicializováno (uninitialized)
‚X‘ Nedefinovaná hodnota mezi 0 a 1
‚0‘ Logická 0 (silná)
‚1‘ Logická 1 (silná)
‚Z‘ Vysoká impedance (3. stav v třístavové logice)
‚W‘ Nejistá hodnota mezi L a H(slabě buzená)
‚L‘ Slabá logická 0
‚H‘ Slabá logická 1
‚-‚ Hodnota, která nás nezajímá

Důvod, proč jsou zavedeny všechny ty nejrůznější slabé hodnoty, je ten, aby bylo možné vytvářet různé „montážní OR“ a „montážní AND“ a aby bylo snazší emulování obvodů. V praxi byste měli používat právě std_ulogic. Klasická „dvouhodnotová“ (ve skutečnosti jich má víc) logika je z ní odvozená a jmenuje se std_logic. Její použití může být nevýhodné, protože v některých situacích musí syntetizér (to je ten software, který převádí VHDL na konkrétní fyzickou reprezentaci) používat resolve funkci, která jasně rozhodne, jestli je signál 0, nebo 1, což může návrh zesložitit nebo zpomalit překlad. Na druhou stranu když si necháte nějakou komponentu vygenerovat, nebo použijete hotový návrh, bude používat s největší pravděpodobností právě std_logic. Více najdete třeba v téhle pěkné diskusi. Já budu v příkladech používat std_logic. (Vaše výhrady k tomuto rozhodnutí přijímám každý den od 13.30 do 13.41 na lampárně hlavního nádraží v Mladé Boleslavi.)

Pokračujme dál.

Slovo „entity“ uvozuje deklaraci, tedy tu část, kde popíšeme rozhraní. Tvar, jaký je uvedený výše, je ten nejčastější, s jakým se setkáte. Obecně:

Jméno entity je zcela na vás, ale musí dodržovat základní pravidla pro pojmenování, podobná těm v ostatních jazycích:

  • Obsahuje velká a malá písmena, číslice a podtržítko
  • Začíná písmenem (ne číslicí ani podtržítkem)
  • Nerozlišují se velká a malá písmena (ADDER je totéž co Adder)
  • Nesmí končit podtržítkem
  • Nesmí obsahovat dvě podtržítka za sebou (Takhle__Ne)

Deklarace je ukončena slovem „end“. Ve VHDL je mnoho ENDů (end if, end component atd.), a proto je dobré zvyknout si psát, k jaké struktuře se ten který end váže. Zde třeba „end entity“. Jak entity, tak její jméno je u „end“ nepovinné, ale může být. Radím zvyknout si, že vždy píšete, k čemu end patří.

Uvnitř deklarace je pouze port(). Ještě se zde může vyskytnout část generic, ale o té později, popř. část definic, deklarací a příkazů. V sekci port() – závorky zde musí být – je deklarováno, jaké má daná komponenta rozhraní. Seznam jednotlivých signálů se skládá z položek ve tvaru „jméno signálu: mód typ“, oddělených středníkem. Za poslední deklarací signálu nesmí být středník! Naopak musí být za závorkou, ukončující port()! Mnoho chyb takhle vzniká…

Jméno signálu má zase stejná pravidla jako jiná jména, viz výše, mód je IN, OUT nebo INOUT, která naznačují, jestli signál do obvodu vstupuje, vystupuje z něj, nebo jestli je obousměrný.

Typ je například už výše zmiňovaný std_logic. Může to být i std_ulogic, popřípadě vektor (tedy několik signálů spojených do jednoho vícebitového), anebo něco zcela jiného (integer, uživatelsky definovaný typ…) Pro tuto chvíli zůstaňme u std_logic.

Naše sčítačka má tedy dva vstupní a dva výstupní signály.

V části „architecture“ je popsáno fungování obvodu (programátorským slangem jde o definici, zatímco entita byla deklarace). Tvar je obecně takový:

Jméno architektury je zase libovolné. V naprosté většině případů budete vytvářet pro entitu jen jednu jedinou architekturu, a pak je úplně jedno, jak se jmenuje. Ale vězte, že architektur můžete mít pro jednu entitu víc, každou jinak pojmenovanou, a v určitých případech (např. při testování) se na ně odvolávat. Architektura se vztahuje k nějaké entitě, a její jméno je zase uvedené v hlavičce

Za hlavičkou („architecture …. of … is“) je část lokálních deklarací. Zde si definujeme typy nebo signály, které jsou použité v rámci architektury (analogicky: lokální proměnné v rámci bloku). Pak následuje vlastní výkonná část architektury, uvozená slovem „begin“, a celé to končí zase slovem „end“ – a stejně jako výš i tady doporučuju naučit se psát „end architecture“.

V naší sčítačce nepotřebujeme žádné lokální signály, jsou to vlastně jen dvě logické funkce. Bude nejjednodušší je popsat právě „data flow“ modelem, kdy řekneme, že „signál Q nabyde hodnoty A xor B“ a „signál Cout nabyde hodnoty A and B“.

Znovu opakuju: Není to tak, že by se NEJDŘÍV přiřadila nějaká hodnota do Q, a POTOM jiná do Cout. Obojí se provádí najednou, protože to syntetizér převede do zapojení logických obvodů. Není to program, je to popis toho, jak vznikají výstupní hodnoty. Pokud máte tendenci dívat se na tento zápis jako na zápis programu, považujte ho za „atomickou operaci“, která proběhne „najednou a nedělitelně“ a na konci bude mít nějaký výsledek.