42
Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra řídicí techniky ČVUT-FEL v Praze

Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

Verze 1.0 ze dne 13. září 2013

Příkladný úvod do VHDL

Richard Šusta

Katedra řídicí techniky

ČVUT-FEL v Praze

Page 2: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

2

Obsah

0. Úvod ..................................................................................................................................................... 4

1. VHDL stylem "Dataflow" .................................................................................................................... 5

1-1 Majorita ze tří — úvod do VHDL a prostředí Quartus II .......................................................... 5

1-1.a) Schéma obvodu v symbolickém editoru ........................................................................... 5

1-1.b) Vytvoření VHDL kódu ..................................................................................................... 5

1-1.c) Jak VHDL program použijeme v grafickém editoru schémat? ........................................ 6

1-1.d) Vysvětlení VHDL majority: knihovny na řádku 2 až 3.................................................... 7

1-1.e) Vysvětlení VHDL majority: Blok entita — řádky 5 až 12 ............................................... 8

1-1.f) Vysvětlení VHDL majority: Definice port — řádky 6 až 9 .............................................. 8

1-1.g) Vysvětlení VHDL majority: Architektura — řádky 12 až 15 ........................................ 10

1-1.h) Vysvětlení VHDL majority: Příkazový blok— řádka 14 ............................................... 11

1-2 Rozšířená majorita ze tří — VHDL signály ........................................................................... 11

1-2.a) Postup rozšíření VHDL majority o další výstup ............................................................. 11

1-2.b) O definici "signal" na řádce 13 ....................................................................................... 13

1-2.c) Více o <= "concurrent assignment" ................................................................................ 14

1-2.d) Otestování upravené majority ......................................................................................... 14

1-2.e) Co když potřebujeme nerozšířenou verzi majority? ....................................................... 15

1-3 Dekodér pro ukazatel — příkazy with…select jazyka VHDL ................................................ 16

1-3.a) Příkaz with…select ......................................................................................................... 16

1-3.b) Datový typ std_logic versus std_logic_vector ................................................................ 17

1-3.c) Tvorba vlastních typů a atributy VHDL ......................................................................... 18

1-3.d) Dekodér pro lineární ukazatel s výstupy na jednotlivé vodiče ....................................... 19

1-4 Prioritní dekodér — VHDL příkaz when…else ..................................................................... 20

1-4.a) Operátory porovnání a logické operátory ve VHDL ...................................................... 21

1-4.b) Pohled do nitra překladače přes RTL Viewer ................................................................ 22

1-5 Tříbitový prioritní inhibitor — cyklus for-generate ................................................................ 23

1-5.a) Jak vložit do výjimky do VHDL — příkazy generic a assert ........................................ 25

1-5.b) Co programu ještě chybí? ............................................................................................... 26

2. VHDL stylem "Structural" ................................................................................................................ 27

2-1 Použití prioritního inhibitoru ve VHDL ................................................................................. 27

2-1.a) Sekce port map a generic map ......................................................................................... 28

2-1.c) Sekce map a schéma ........................................................................................................ 29

2-1.c) Mapování vstupů a výstupů pro desku DE2 .................................................................... 30

2-2 Rozšíření prioritního inhibitoru o enable ............................................................................... 30

2-2.a) Inicializace proměnných vektorů asociací others=> ....................................................... 31

2-3 Vytvoření vlastní knihovny ("package") ................................................................................. 32

2-3.a) Dekodér pro lineární ukazatel s výstupy na jednotlivé bity pomocí knihovny .............. 33

2-4 Zapojení prioritního dekodéru a lineárním ukazatelem .......................................................... 33

Závěr ....................................................................................................................................................... 35

Příloha A: Testbench pro ModelSim ..................................................................................................... 36

A-1 Vytvoření programu typu Testbench ...................................................................................... 36

A-2 Spuštění Testbench v ModelSim Altera .................................................................................. 39

Page 3: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

3

Seznam programů

Program 1 - Majorita ze tří ................................................................................................................... 6

Program 2 - Pořadí vstupů a výstupů v entitě a ve schematické značce ............................................ 10

Program 3 - Majorita s pomocným výstupem jednoho signálu ......................................................... 12

Program 4 - Dekodér pro lineární ukazatel ........................................................................................ 16

Program 5 - Dekodér pro ukazatel s oddělenými výstupy ................................................................. 19

Program 6 - Prioritní dekodér ............................................................................................................. 20

Program 7 - Zbytečné podmínky v příkazu when...else ..................................................................... 21

Program 8 - Program pro demonstraci práce s proměnnými datového typu Boolean ....................... 21

Program 9 - Minimalizovaná kaskáda multiplexorů .......................................................................... 22

Program 10 - Java metoda pro vyzkoušení prioritního inhibitoru ..................................................... 23

Program 11 - Prioritní inhibitor pro 18 vstupů a výstupů .................................................................. 24

Program 12 - Prioritní inhibitor s generic .......................................................................................... 25

Program 13 - Prioritní inhibitor ve strukturálním popisu ................................................................... 27

Program 14 - Nedoporučené použití neúplných definic v bloku "component"! ................................ 28

Program 15 - Automaticky generovaný VHDL kód .......................................................................... 29

Program 16 - Prioritní inhibitor s enable vstupem ............................................................................. 30

Program 17 - Demonstrace použití others pro inicializaci ................................................................. 31

Program 18 - Knihovna kódů vytvořených v úvodu do VHDL ......................................................... 32

Program 19 - Dekodér pro lineární ukazatel s výstupy na jednotlivé bity pomocí knihovny ............ 33

Program 20 - Prioritní dekodér s výstupem na lineární ukazatel ....................................................... 34

Program 21 - VHDL testbech pro dekoder dekodér s výstupem na lineární ukazatel ....................... 37

Seznam obrázků

Obrázek 1 - Majorita ze tří .................................................................................................................. 5

Obrázek 2 - Realizace módů v obvodu ................................................................................................ 9

Obrázek 3 - Schéma odpovídající přiřazení y <= a AND b OR a AND c OR b AND c; ......... 11

Obrázek 4 - Upravená majorita .......................................................................................................... 13

Obrázek 5 - Důsledek chybného dvojího přiřazení hodnot do signálu ytmp ..................................... 13

Obrázek 6 - Aktualizace změněného symbolu ................................................................................... 14

Obrázek 7 - Výsledné schéma v test.bdf ............................................................................................ 15

Obrázek 8 - Rozšířená majorita s nezapojeným výstupem y1 ........................................................... 15

Obrázek 9 - Operace s std_logic_vector ............................................................................................ 17

Obrázek 10 - Dekodér pro lineární ukazatel s bitovými I/O .............................................................. 19

Obrázek 11 - Prioritní dekodér z multiplexorů .................................................................................. 20

Obrázek 12 - Vyvolání RTL Viewer z top-level entity ...................................................................... 22

Obrázek 14 - Ukázka použití prioritního inhibitoru ve schématu ...................................................... 25

Obrázek 13 - Příklad použití prioritního inhibitoru ........................................................................... 25

Obrázek 15 - Příkaz "Create HDL Design File" ................................................................................ 29

Obrázek 16 - Test inhibitoru 2 vložený do schématu ......................................................................... 30

Obrázek 17 - Prioritní dekodér s lineárním ukazatelem ..................................................................... 33

Obrázek 18 - Breakpoint při simulaci ................................................................................................ 42

Page 4: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

4

0. Úvod

Proč zrovna VHDL?

VHDL patří mezi HDL programovací jazyky ("Hardware Description Languages") určené pro ná-

vrhy obvodů. V USA se převážně používá HDL jazyk Verilog, se syntaxí podobnou jazyku C, zatímco

v Evropě se více programuje ve VHDL ("Very-high-speed integrated circuits Hardware Description Lan-

guage"), vzdáleně se podobajícímu PASCALu. (Přesněji — VHDL si vypůjčilo mnoho své syntaxe z jazy-

ka ADA, u nás méně známého, který se mírně podobá PASCALu.)

Když jsme se v roce 2009 rozhodovali, zda studenty učit VHDL či Verilog, mnozí profesionální

návrháři, kteří léta používají oba jazyky, se klonili k VHDL. Jde o jazyk sice upovídaný a typově ještě

striktnější než PASCAL, avšak návrhy v něm mají lepší šanci fungovat. Jazyk Verilog má ve své podob-

nosti s jazykem C jen zdánlivou výhodu; postupy osvojené z C programů se nehodí pro obvody.

Zde si nutno poznamenat, že HDL jazyky mají trojí použití: 1/ pro specifikaci obvodů, 2/ pro jejich

simulaci a 3/ pro jejich fyzickou syntézu. Kvůli tomu obsahují široké spektrum programových konstrukcí,

ale pro syntézu obvodů se hodí jen některé z nich.

Účel učebního textu

Následující text vznikl na základě dlouholetých zkušeností s výukou kurzu SPS (Struktury počíta-

čových systémů) na Katedře řídicí techniky Elektrotechnické fakultě v Praze. Používá se v něm VHDL

jako pomocný nástroj pro laboratorní experimenty s počítačovými systémy a paralelním chováním jejich

obvodů — bez HDL jazyků se dnes již nedá rozumně pracovat. Studenti ale nebudou většinou profesio-

nálně navrhovat hardware a potřebují jen jeho základy, ale i ty by měli znát na technické úrovni odpoví-

dající vysoké škole. Při psaní dobrých VHDL programů je třeba občas pomyslet na strukturu vytvářeného

zapojení a nelze jen mechanicky "bušit" jakési programové příkazy.

V češtině existuje několik učebnic VHDL i webových stránek s jeho popisy, avšak často bývají pří-

liš programátorské, soustředěné na samotný jazyk, a navíc postrádají vazby k vhodnému vývojovému

prostředí, ve kterém by se daly návrhy obratem vyzkoušet.

Organizace textu

Výklad bude vycházet z příkladů cílených na FPGA vývojovou desku DE2 firmy Altera. Začneme

od lehké majority ze tří, kterou použijeme nejen k úvodu do VHDL, ale současně i k návodu jak pracovat

s VHDL v prostředí Altera Quartus II. Kvůli tomu doporučuji i pokročilejším čtenářům, aby si úvodní

příklad udělali úplně celý. Další části pak budou věnované více jazyku VHDL.

Prerekvizity

V úvodu do VHDL budeme přepokládat, že čtenáři

mají instalované programovací prostředí Quartus II od firmy Altera, jehož bezplatnou verzi Quartus II

Web Edition Software si lze stáhnout ze stránek firmy po registraci či z webu SPS. Umožní práci jen

s některými FPGA, ale se všemi potřebnými v kurzu SPS, a nepovoluje dílčí překlady částí obvodů;

vždy překládá vše, což u menších návrhů nevadí. Jinak nabízí stejnou funkčnost jako komerční verze.

mají správně vytvořený projekt v Quartus II určený pro desku DE2, a to včetně přiřazení odpoví-

dajících "Pin Assignments" desky DE2 ze souboru "DE2_pin_assignments.csv" ;

ovládají práci ve vývojovém prostředí Quartus II na úrovni symbolického editoru.

Pokud někomu uvedené znalosti chybí, může je získat z materiálů na stránce předmětu SPS:

https://moodle.dce.fel.cvut.cz/course/view.php?id=5

Rada: Text obsahuje krátké příklady. Úmyslně nepřikládám jejich zdrojové kódy. Nekopírujte si je z ob-

razovky. Prostudujte si vždy celý příklad a pak si ho vytvořte zpaměti od začátku — a pokud možno

s minimem pohledů na text. Metodou "Copy-Paste" se ještě nikdo nic nenaučil !

Page 5: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

5

1. VHDL stylem "Dataflow" Popis stylem "dataflow", tedy pomocí toku dat, se hodí

pro části popsané kombinačními obvody, v nichž závislost výstupů na vstupech lze popsat logický-

mi operacemi.

1-1 Majorita ze tří — úvod do VHDL a prostředí Quartus II Zadání: Navrhněte logický obvod se třemi vstupy A, B a C a jedním výstupem Y, který bude v lo-

gické ´1´, pokud dva nebo tři vstupy budou v logické ´1´, jinak bude v logické ´0´.

1-1.a) Schéma obvodu v symbolickém editoru

Řešení:

Výstup má být v logické ´1´ při libovolných dvou vstupech

v ´1´. Ze tří vstupů lze vytvořit tři dvojice A-B, A-C a B-C.

Pokud jejich členy spojíme v AND-termy (oba vstupy

v dvojici jsou v ´1´) a ty sloučíme OR operacemi (aspoň jedna

dvojice musí být v ´1´), pak dostaneme

Y = (A and B) or (A and C) or (B and C). Stejný výsledek dá i SoP (Sum-of-Products) pokrytí Kar-

naughovy mapy.

Navržený obvod lze vytvořit v grafickém editoru sou-

borů *.bdf (Block Diagram/Schematic File) ze tří hradel AND

a jednoho hradla OR.

1-1.b) Vytvoření VHDL kódu

Lze použít jakýkoliv textový editor. Výborně se hodí interní VHDL editor v Quartus II, který už od

verze 11 nabízí zvýraznění syntaxe a automatické doplňování kódu po napsání prvních tří písmen.

Vytvoříme nový soubor VHDL z hlavního menu Quartusu (File->New -> VHDL file) a uložíme ho

(File->Save As) pod názvem vytvářeného obvodu — tím bude název v jeho bloku entity, viz dále.

Zvolíme-li pro entitu název majorita, pak VHDL soubor musíme nazvat majorita.vhd.

Poznámka: Ve VHDL se každý obvod (entita) ukládá do stejnojmenného souboru, jelikož překladač

právě tohle předpokládá.

o Alternativní možností je komerční editor Sigasi (http://www.sigasi.com). Jeho bezplatná verze

nabízí vše pro menší soubory a pro větší se přepne na omezené možnosti. Obsahuje i trochu

pokročilejší ediční funkce; jako třeba přejmenování proměnných ("Refactor") a zvýraznění

chyb při psaní. V budově FEL na Karlově náměstí lze používat i jeho plnou verzi jako pomoc-

ný editor — Quartus II detekuje externě změněné soubory a nabídne jejich aktualizaci.

Komentáře ve VHDL začínají dvojicí pomlček "- - " a končí s koncem řádku. Neexistuje sice mož-

nost jak komentovat celé bloky, třeba označit každý řádek zvlášť, ale Quartus II i Sigasi dovedou vlo-

žit komentářové pomlčky na začátky všech řádek ve vybraných blocích a případně je zas odebrat.

Raději nepoužívejte diakritiku, a to ani v komentářích. Překladače ji někdy vezmou, jindy ne. Spo-

lehlivě rozumí jen čistému ASCII. Pozn. VHDL programy nebudete překládat jen v Quartusu, ale pro

simulace i v ModelSim, a tak se hodí dodržet kompatibilitu pro oba překladače.

VHDL nerozlišuje malá a velká písmena. Nicméně bývá dobrým zvykem psát proměnné a klíčová

slova pořád stejně. I když "entity", "Entity", "ENTITY" i "EnTiTy" bere překladač jako stejné slovo,

program bude mnohem přehlednější, budeme-li psát vždy "entity".

Y

Majorita ze tří A

B

C

0 0

0 1

1 0

1 1C

A

A.B + A.C + B.C

B

Obrázek 1 - Majorita ze tří

Page 6: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

6

VHDL kód uvedeme napřed celý, poté ukážeme jeho použití v editoru schémat, což nám posléze umožní

lépe vysvětlit jeho části:

-- Majorita ze tri -- 1 library ieee; -- 2 use ieee.std_logic_1164.all; -- 3 -- 4 entity majorita is -- 5 port -- 6 ( a, b, c : in std_logic; -- 7 y : out std_logic -- 8 ); -- 9 end; -- 10 -- 11 architecture dataflow of majorita is -- 12 begin -- 13 y <= (a AND b) OR (a AND c) OR (b AND c); -- 14 end; -- 15

Program 1 - Majorita ze tří

1-1.c) Jak VHDL program použijeme v grafickém editoru schémat?

Pro začlenění do schématu volíme následující postup. VHDL program napřed otestujeme, zda ne-

obsahuje syntaktickou chybu (ikona nad T šipkou) v obrázku dole, či ho přeložíme; označíme majorita.vhd

za hlavní entitu a spustíme buď částečný překlad ikonou pod C šipkou či úplný ikonou pod P šipkou.

Symbol (tj. schematickou značku) pro majoritu vytvoříme buď: 1/ v okně "Project Navigator" pře-

pnutém na záložku "Files" vybereme soubor majorita.vhd, pravou myší otevřeme jeho kontextové menu

a volíme "Create Symbol File for Current File." (S-šipka); nebo 2/ při VHDL souboru otevřeném

v editoru volíme z hlavního menu Quartusu: "File-> Create/Update ->Symbol Files for Current Files".

Nyní můžeme program vyzkoušet. Vytvoříme nový "Block Diagram/Schematic File" (File->New),

a nazveme ho třeba jako test.bdf a otevřeme v něm "Symbol Tool" buď z lišty nástrojů editoru schémat

(viz dole obr. a), nebo alternativně pravým dvojklikem myši kamkoliv na prázdné místo grafické plochy.

Page 7: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

7

a) Vložení bloku přes Symbol Tool b) Vygenerování vstupů a výstupů

V dialogovém okně "Symbol" se nám přidala knihovnu "Project", z níž vybereme entitu majorita. Vlo-

žíme ji do schématu. Připojíme k ní vstupy a výstupy pro její vyzkoušení, a to buď manuálně, nebo si

můžeme ušetřit trochu práce, když pravou myší vyvoláme kontextové menu vložené schematické značky

majorita (viz předchozí obr. b) a necháme si pro ni automaticky vygenerovat vstupy a výstupy volbou

"Generate Pins for Symbol Ports". Vložené "pins" jen přejmenujeme podle "assignments" desky DE2.

Nyní zvolíme test.bdf za hlavní entitu, přelo-

žíme ji a nahrajeme do desky DE2. Přepínači SW

vyzkoušíme, že výstup je v ´1´ jen tehdy, když

nejméně dva SW jsou v pozici nahoru, tj. v ´1´.

Nemáte-li desku, alternativní možností je využití

v simulátoru, viz materiály na stránce kurzu.

c) Schéma po přejmenování podle definic desky DE2

Překladači nezáleží na tom, zda jsme entitu vytvořili ve VHDL nebo v symbolickém editoru. Oba

přístupy jsou v mnohých operacích skoro rovnocenné, ovšem ne v pracnosti, složitější obvody se rychleji

navrhnou ve VHDL, kde se dají i snáze porovnávat verze programu než u schémat.

1-1.d) Vysvětlení VHDL majority: knihovny na řádku 2 až 3

Probírání strukturu kódu VHDL začneme od knihoven. -- Majorita ze tri -- 1

library ieee; -- 2 use ieee.std_logic_1164.all; -- 3 -- 4 entity majorita is -- 5 port -- 6 ( a, b, c : in std_logic; -- 7 y : out std_logic -- 8 ); -- 9 end; -- 10 -- 11 architecture dataflow of majorita is -- 12 begin -- 13 y <= (a AND b) OR (a AND c) OR (b AND c); -- 14 end; -- 15

Příkaz "library" (řádek 2) aktivuje knihovnu, zde standardní ieee navrženou v "Institute of Elec-

trical and Electronics Engineers (IEEE)". Na řádku 3 se z ní vybírá balíček ("package") deklarující stan-

dardní logiku "std_logic_1164" a z něho vezmeme vše (all). Pozn. Volba "all" je nejčastější, ale

z knihovny lze též vybrat i jeden prvek, což se někdy hodí pro řešení konfliktů u složitějších projektů.

Řádky 2 a 3 jsou v úvodu téměř každého VHDL programu napsaného pro standardní logické

obvody. Můžete je mechanicky vkládat na začátek každého nového souboru, který vytvoříte v kurzu SPS.

Page 8: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

8

Poznámka: Snadná práce s knihovnami představuje výhodu VHDL oproti Verilogu, který zde nabízí

mnohem omezenější možnosti.

1-1.e) Vysvětlení VHDL majority: Blok entita — řádky 5 až 12

Návrh obvodu povinně obsahuje deklaraci bloku entity, v našem programu na řádku 5:

entity majorita is

kde entity je klíčové slovo a "majorita" představuje námi přiřazený název obvodu shodný se jménem

VHDL souboru (majorita.vhd). Blok entity může obsahovat několik definic (ale nemusí mít ani jednu,

může být i prázdný). Náš příklad má jedinou definici, a to "port", proměnných vstupů a výstupů.

Na řádku 10 blok entity končí klíčovým slovem

end;

Zakončení lze napsat zkráceně, tak jako v našem příkladu, nebo případně za end zopakovat

i klíčové slovo entity nebo také název, což se povoluje od verze VHDL-93 (používané v kurzu SPS).

Konec našeho bloku entity může mít tedy některý z tvarů:

entity majorita is -- deklarace end;

entity majorita is -- deklarace end entity;

entity majorita is -- deklarace end majorita;

entity majorita is -- deklarace end entity majorita;

Tabulka 1 - možnosti zakončení deklarace entity ve VHDL-93 a vyšším

Zkracování ukončujících "end" se povoluje i u některých dalších deklarací, například také u bloku

architecture na rádcích 12 až 15, kde možno uplatnit stejný princip. Volba zakončení závisí jen na progra-

mátorovi. U kratších bloků se volí jen end, u delších deklarací bývá lepší pro zvýšení přehlednosti pro-

gramu zopakovat klíčové slovo úvodní deklarace bloku, zde entity, nebo přidat i název bloku či obojí.

Blok entity určuje vnější vzhled obvodu, čili jak obvod uvidíme po vložení jeho instance do sché-

matu, viz ukázka použití v editoru schémat; kvůli tomu jsme ji uvedli před rozborem programu.

VHDL blok entity se obecně chová úplně jinak než třídy známé z C++, Javy a C#, nicméně může-

me říct, že lze najít nepatrnou analogie v tom, že název uvedený v úvodu bloku entity odpovídá jménu

třídy — s odvoláním na něj vytváříme instance třídy, ve VHDL obvodu.

1-1.f) Vysvětlení VHDL majority: Definice port — řádky 6 až 9

Definice port se může objevit jen uvnitř deklara-

ce entity a nejvýše jen jednou. Specifikuje proměnné

vstupů a výstupů, tedy jakési analogie prvků "public"

tříd viditelných zvnějšku. Obsahuje seznamy proměn-

ných spolu se seznamy jejich názvů (signal-names),

datovými typy (signal-type) a módy (mode) určujícími

druh vstupu či výstupu. Pozn. Všimněte si, že za po-

sledním signal-type chybí středník — jeho napsání

bývá častou syntaktickou chybou začátečníků.

-- Majorita ze tri -- 1 library ieee; -- 2 use ieee.std_logic_1164.all; -- 3 -- 4 entity majorita is -- 5

port -- 6

( a, b, c : in std_logic; -- 7

y : out std_logic -- 8 !! ZA POSLEDNI DEFINICI NENI ; !!

); -- 9

end; -- 10 -- 11 architecture dataflow of majorita is -- 12 begin -- 13 y <= (a AND b) OR (a AND c) OR (b AND c); -- 14 end; -- 15

Page 9: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

9

• Názvy proměnných a bloků: VHDL názvy začínají písmenem A-Z a pokračují písmeny a číslicemi

0-9. Malá a velká písmena se nerozlišují, ale doporučuje se psát názvy pořád stejně. Název nesmí být

klíčovým slovem. Může obsahovat znaky podtrhávače _, avšak nikoliv na začátku nebo konci názvu,

nebo dva podtrhávače za sebou. Povolené názvy: A1, A_1, A12_b7_Z

Nepovolené názvy: A1_ (podtrhávač na konci), A__1 (dva podtrhávače), end (klíčové slovo),

A$B (nepovolený znak $.).

• VHDL od verze 93 dovoluje i rozšířené názvy ohraničené znaky \ \ — v těch lze použít i zakázané

konstrukce. Například dovolené rozšířené názvy jsou \123.45\ , \END\ či \A$B\. Slouží pro speciál-

ní operace a kódy automaticky generované překladači. V běžných programech se z důvodu kompati-

bility doporučuje používat normální názvy.

• V delších programech volíme názvy vždy výstižné, specifikující účel či použití.

• Mód proměnné: Ve většině návrhů se používají jen módy in a out. Mód in označuje vstup, jehož

hodnotu lze zvnitřku obvodu jen číst, ale nelze do něho zapisovat. Naproti tomu mód out specifikuje

výstup, jemuž můžeme zvnitřku obvodu přiřadit hodnotu, ale nelze ho číst.

• Pokud musíme hodnotu výstupu i číst, lze použít mód

buffer, ovšem pro něj musí překladač vyhradit trochu

obsažnější element, jelikož z výstupu vede drát zpět do

vnitřku obvodu.

• Posledním módem je typ inout, který dovoluje data

jak číst tak do nich zapisovat. Vyžaduje ovšem složitý

prvek obousměrného budiče, a tak se používá jedině

výjimečně, například pro obousměrné směrnice jako

třeba sběrnice I2C (na desce DE2 je přes ni připojený

audio výstup).

Obrázek 2 - Realizace módů v obvodu

• V návrzích určených pro syntézu obvodů se doporučuje používat přednostně módy in a out.

Pozn. O portech se zmíníme ještě v sekci "1-2.b) O definici "signal" na řádce 13" na str. 13.

• Datové typy: Pro vstupy a výstupy se používají typy odvozené od std_logic, což je proměnná výčto-

vého typu obsahující 9 hodnot: '1', '0', 'X', 'Z','U', '-', 'L', 'H', 'W' vícehodnotové logiky zvané MVL-9

(Multi Value Logic 9). Pomocí ní lze dobře popsat i neurčitost při návrhu a simulacích obvodů.

Datové typy odvozené od std_logic se při VHDL syntéze volí pro další proměnné spojené v toku dat

se vstupy a výstupy, neboť překladače je mohou lépe syntetizovat.

Unitialized ´U´ objeví se zpravidla jen při simulaci obvodu, kdy díky nezadané inici-

alizaci není možné stanovit hodnotu výstupu

Don’t Care ´-´ v návrhu dosud nezadaná hodnota

Forcing 1 ´1´ logická 1

Forcing 0 ´0´ logická 0

Forcing Unknown ´X´ neznámá hodnota, při simulaci ji nelze stanovit

Weak 1, Weak 0, Weak unknown

´H´,´L´, ´W´

vhodné pro obvody s otevřeným kolektorem, FPGA řady Cyclone je

ale neobsahují, a tak u nich nelze použít

High Impedance ´Z´ odpojení výstupu, třetí stav vysoké impedance

Tabulka 2 - Typ std_logic

• Pozn. VHDL obsahuje i jednobitové datové typy "Boolean" a "Bit", oba opět realizované jako výčto-

vé typy. Typ "Boolean" s hodnotami TRUE a FALSE lze použít jedině pro podmínky, viz dále. Typ

"Bit" s hodnotami ´0´ a ´1´ se zase hodí jen pro generátory simulací či podobné pomocné výpočetní

části. Striktně se nedoporučuje používat ho v programech pro syntézu obvodů, protože překladač pak

nedetekuje některé obvodové chyby, jako například dva zdroje signálu ve zkratu.

Page 10: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

10

Pozor —datové typy std_logic a bit nejsou převoditelné žádným přetypováním.

• Pořadí definic v bloku port je sice libovolné, ale určujeme tím pořadí vstupů a výstupů na schema-

tické značky, a proto ji pro schéma musíme po každé změně definice port znovu vygenerovat pomocí

již zmíněného "Create Symbol File for Current File". V definicích port lze použít buď seznam pro-

měnných od sebe oddělených čárkami, tak jako v Program 1 na str. 6, nebo každou proměnnou psát

na samostatný řádek, což dovoluje přidat k ní komentář jejího významu. Komentáře zde vynecháváme

jen pro zkrácení délek řádek, ale v dobrém kódu by je měly být u každého vstupu a výstupu.

entity majorita is

port ( b : in std_logic;

y : out std_logic; c : in std_logic;

a : in std_logic );

end;

Program 2 - Pořadí vstupů a výstupů v entitě a ve schematické značce

1-1.g) Vysvětlení VHDL majority: Architektura — řádky 12 až 15

Blok architektury popisuje vlastní obvod. V programu majorita začíná na řádku 12, a to klíčovým

slovem architecture, za nímž následuje jméno vytvářené architektury a název entity, pro niž je archi-

tektura určená. Poté následuje příkazový blok begin end; připomínající bloky v Pascalu.

Blok entity se v některých publikacích připodobňuje k interface v Pascalu a blok architektury zase

k vlastní implementaci. Lépe by se možná hodila jiná podobnost přirovnávající obvod ke krabičce s elek-

tronickým přístrojem, třeba se zesilovačem. Entita pak představuje ovládací prvky vyvedené na povrch

krabičky, jako třeba vstupy signálu z mikrofonu, kytary nebo přehrávače, zdířky pro připojení výstupů na

reproduktory či sluchátka a voliče zesílení. Architektura se zde podobá vnitřnímu zapojení zesilovače,

skrytému před vnějším pozorovatelem uvnitř krabičky. Lze měnit ovládací prvky na povrchu krabičky (tj.

entitu) a přizpůsobit jim vnitřní zapojení (tj. architekturu), nebo naopak měnit jen vnitřní zapojení pro

vylepšení funkce a plně zachovat ovládací prvky, či změnit oboje. -- Majorita ze tri -- 1 library ieee; -- 2 use ieee.std_logic_1164.all; -- 3 -- 4 entity majorita is -- 5 port -- 6 ( a, b, c : in std_logic; -- 7 y : out std_logic -- 8 ); -- 9 end; -- 10 -- 11

architecture dataflow of majorita is -- 12

begin -- 13

y <= (a AND b) OR (a AND c) OR (b AND c); -- 14

end; -- 15

Název architektury dataflow byl zvolený podle stylu programu. Naši entitu majorita popisuje-

me architekturou ve stylu "dataflow", a tak jsme ji tak nazvali. Každý název architektury patří jen do

jmenného prostoru identifikátorů své entity. Jinými slovy — u dalších entit můžeme jejich architektury

opět nazvat dataflow, budou-li popsané tímto stylem.

Pozn. Povinný název architektury slouží pro případy, kdy entita má několik různých architektur, tj.

více bloků architecture pro jednu entitu. Víc různých architektur se hodí například tehdy, když potře-

bujeme jednu funkci obvodu pro jeho samotnou realizaci a další pro jeho urychlení při simulacích. Pou-

žívání několika architektur, samozřejmě odlišených různými názvy, představuje už pokročilejší téma —

v kurzu SPS vystačíte s jednou architekturou pro každou entitu.

b

c

a

y

majorita

inst

Page 11: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

11

Pro zakončení bloku architektury klíčovým slovem end platí podobné možnosti jako pro zakon-

čení bloku entity. Za klíčovým slovem end možno zopakovat i klíčové slovo architecture i její název

dataflow, podobně jako u zakončení bloku entity, viz Tabulka 1 na straně 8.

1-1.h) Vysvětlení VHDL majority: Příkazový blok— řádka 14

Vlastní implementace architektury zaujímá jedinou řádku 14. Obsahuje logický výraz a přiřazovací

příkaz <= označovaný jako "concurrent assignment", tedy souběžné, resp. paralelní přiřazení. Všechna

taková přiřazení se provádějí současně, bez ohledu na jejich pořadí. V našem jednoduchém příkladu má-

me však jen jedno, a tak ho více rozebereme v další části, kde si náš příklad rozšíříme o další výstup.

Logický výraz obsahuje operátory AND a OR. VHDL jazyk definuje následující operátory se jmé-

ny odpovídajícími běžným názvům hradel, ale rozeznává pouze dvě priority. Nejvyšší má unární operátor

negace NOT, zbylé operátory mají stejnou prioritu, závorky jsou ve výrazech nezbytností.

Vyšší priorita not Nižší priorita and or nand nor xor xnor

Tabulka 3 - Logické operátory jazyka VHDL

Pokud bychom v našem výrazu

y <= (a AND b) OR (a AND c) OR (b AND c);

vynechali závorky a napsali ho jako

y <= a AND b OR a AND c OR b AND c;

pak by se ve skutečnosti realizovalo zapojení odpovídající výrazu

y <= (((((a AND b) OR a) AND c ) OR b) AND c);

a schématu s úplně jinou funkcí:

Obrázek 3 - Schéma odpovídající přiřazení y <= a AND b OR a AND c OR b AND c;

1-2 Rozšířená majorita ze tří — VHDL signály Zadání: Rozšiřte majoritu o další výstup Y1, který bude signalizovat, že jen jeden vstup je ve stavu

logické ´1´ a ostatní jsou v ´0´.

Řešení: Máme dvě možnosti.

1) Přidáme rovnici pro další výstup Y1, ten bude v ´1´ pouze při jednom vstupu v ´1´, tzn. za některé

kombinace vstupů ABC = "100", "010" a "001". Podmínku můžeme vyjádřit logickou rovnicí:

Y1 <= (A AND not B AND not C) or (not A AND B AND not C) OR (not A AND not B AND C);

2) Uplatníme skupinovou minimalizaci, tj. využijeme již stávající rovnice pro Y. Výstup Y je v ´1´

jen při dvou nebo třech vstupech v ´1´, ve zbývajících případech bude v ´0´, tedy při všech vstupech v ´0´

a právě při jednom vstupu v ´1´. Stačí tedy selektivně vybrat poslední podmínku, k čemuž můžeme použít

OR-term všech vstupů a ten následně spojit AND s negací Y.

Y1 <= not Y AND (A OR B OR C);

Rovnice nám říká, výstup Y1 bude v ´1´ právě tehdy, pokud nebude splněna podmínka majority (not Y)

a aspoň jeden vstup bude v ´1´, což spolehlivě vyloučí nechtěný případ, kdy všechny vstupy jsou v ´0´.

1-2.a) Postup rozšíření VHDL majority o další výstup

V deklaraci entity přidáme pouze výstup Y1.

-- Majorita ze tri s výstupem jednoho signálu -- 1

library ieee; -- 2

a b c

y

Page 12: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

12

V architektuře nelze napsat přímo y1 <= not y AND (a OR b OR c); protože překladač by ohlásil chybu,

že výstup y nelze číst, protože je módu out, viz část "1-1.f) Vysvětlení VHDL majority: Definice port —

řádky 6 až 9" na straně 8.

Museli bychom buď změnit mód výstupu y na buffer, čímž ale zbytečně ztížíme implementaci kó-

du. Lepší řešení nabízí možnost vložení pomocného vodiče; ten se ve VHDL nazývá signal. Pojmenu-

jeme ho ytmp a bude stejného datového typu jako proměnná y, tedy datového typu std_logic. Definici

signálu "signal ytmp : std_logic;" vložíme před příkazový blok begin end architektury

Původní výraz y <= (a AND b) OR (a AND c) OR (b AND c); změníme. Jeho pravou stranu přiřadíme

do signálu ytmp zápisem: ytmp <= (a AND b) OR (a AND c) OR (b AND c); a poté ytmp přiřadíme do y.

Signál ytmp již smíme číst a lze ho použít ve výrazu pro y1.

Celý program bude nyní vypadat takto:

use ieee.std_logic_1164.all; -- 3

-- 4

entity majorita is -- 5

port -- 6

( a, b, c : in std_logic; -- 7

y, y1 : out std_logic -- 8

); -- 9

end; -- 10

-- Majorita ze tri s výstupem jednoho signálu -- 1

library ieee; -- 2

use ieee.std_logic_1164.all; -- 3

-- 4

entity majorita is -- 5

port -- 6

( a, b, c : in std_logic; -- 7

y, y1 : out std_logic -- 8

); -- 9

end; -- 10

-- 11

architecture dataflow of majorita is -- 12

signal ytmp : std_logic; -- 13

begin -- 14

ytmp <= (a AND b) OR (a AND c) OR (b AND c); -- 15

y <=ytmp; -- 16

y1 <= not ytmp AND (a OR b OR c); -- 17

end; -- 18 Program 3 - Majorita s pomocným výstupem jednoho signálu

Page 13: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

13

1-2.b) O definici "signal" na řádce 13

Signály jsou ve skutečnosti pojmenované vodiče neboli propojky. Můžeme je libovolněkrát číst dle

potřeby. Čtení jejich hodnoty vlastně znamená, že z vodiče uděláme odbočku, čili na něj připojíme.

Upravený program majorita vnáší změnu, která je zvýrazněna na obrázku dole. Zakroužkované

hradlo už nemá k sobě připojené přímo Y, (viz dřívější obrázek na str. 5), ale pojmenovaný vodič ytmp

(signal ytmp : std_logic;), připojený <= příkazem: ytmp<=(a AND b) OR (a AND c) OR (b AND c);

Vodič ytmp vede na výstup y, a to příkazem "y <= ytmp;" . Hodnota vodiče (signálu) ytmp se

připojuje i na vstup hradla not (invertoru), a to čtením hodnoty ytmp v y1 <= not ytmp AND (a OR b OR c);

Jelikož signály představují vodiče, můžeme jim hodnotu přiřadit pouze jednou v celém obvodu, ji-

nými slovy lze je připojit jen na jeden zdroj signálu. Dvojí přiřazení by vlastně znamenalo, že vodič bu-

díme ze dvou zdrojů najednou, například máme spojené výstupy dvou hradel do zkratu a ty se přetahují o

výslednou hodnotu.

architecture dataflow of majorita is

signal ytmp : std_logic;

begin

ytmp <= (a AND b) OR (a AND c) OR (b AND c);

y <=ytmp;

ytmp<= ytmp AND (a OR b OR c); -- chybné dvojí přiřazení do ytmp

y1 <= ytmp;

end;

Pokus o dvojí přiřazení, které je v předchozím špatném programu, vyvolá chybu překladače "Can't re-

solve multiple constant drivers for net "ytmp" at majorita.vhd". Co vlastně teď od překladače chceme, to

nám přibližuje obrázek dole, v němž je hypotetická, neproveditelná spojka zvýrazněná červeně.

Pozn. Spojení dvou výstupů se obecně povoluje pouze ve výjimečných případech, například u již

zmíněných obvodů s otevřeným kolektorem, tzv. Wired-Or. DE2 deska s FPGA Cyclone neobsahuje spe-

ciality umožňující zkratovat výstupy, a tak podobné "krkolomnosti" jsou pro ni nepřeložitelné.

Signály a definice vstupů a výstupů sekci v port

I vstupy a výstupy definované v sekci port uvnitř bloku entity jsou ve skutečnosti pojmenované vo-

diče, ovšem vedoucí vně našeho obvodu. Z toho vyplývají všechna jejich omezení

Vodič portu vstupu módu "in" smíme zvnitřku obvodu jen číst, protože bude buzený ze zdroje signálu

přivedeného zvnějšku, tedy ze zapojení, které se připojí k našemu obvodu.

Obrázek 5 - Důsledek chybného dvojího přiřazení hodnot do signálu ytmp

y

y1

ytmp

důsledek chybného dvojího

přiřazení hodnot

do signálu ytmp

c

b

a

y

y1

ytmp b

a

c

Obrázek 4 - Upravená majorita

Page 14: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

14

Naopak do vodiče portu výstupu módu "out" lze zvnitřku obvodu přiřadit hodnotu jenom jedenkrát,

podobně jako do signálů. Jeho hodnota bude k dispozici pro jiná vnější zařízení. Jelikož z výstupu ne-

vede spojka zpět do obvodu, nemůžeme ji zvnitřku obvodu číst.

Do vodiče portu výstupu módu "buffer" se opět smí také zapsat jenom jedenkrát hodnota, ale jelikož

od něho vede spojka dovnitř, smíme i číst jeho hodnotu. Pokud něco takového potřebujeme, pak je

mnohem lepší použít pomocný signál tak, jako v příkladu upravené majority. Definicí buffer bychom

jenom zbytečně komplikovali vnitřní implementaci obvodu.

1-2.c) Více o <= "concurrent assignment"

Všechny příkazy <= "concurrent assignment" se provádějí paralelně bez ohledu, kde a v jakém po-

řadí se v obvodu vyskytují. Například, pokud příkazy z předchozího programu proházíme, třeba úplně

obráceně, pak program bude dál pracovat stejně jako prve bez jakéhokoliv snížení efektivity:

y1 <= not ytmp AND (a OR b OR c);

y <=ytmp;

ytmp <= (a AND b) OR (a AND c) OR (b AND c);

Příkazy definují zapojení a každé zapojení v obvodu pracuje současně se všemi ostatními. Zkuste si

představit, že máte tři lampy či jiná elektrická zařízení. Všechna budou pracovat pořád stejně bez ohledu

na to, v jakém pořadí je připojíte k přívodům přívodů elektrické energie. Důležité je jenom to, že jsou

k němu připojené. Přesně takhle pracují příkazy <= "concurrent assignment".

1-2.d) Otestování upravené majority

Chceme-li upravenou majoritu vyzkoušet ve schématu, musíme provést následující kroky:

a) Napřed potřebujeme vygenerovat nový symbol obvodu majorita, protože jsme změnili definici port

v deklaraci jeho entity. Postup se probíral v podkapitole "1-1.c) Jak VHDL program použijeme v gra-

fickém editoru schémat?" na straně 6.

b) Poté musíme aktualizovat stávající schéma obvodu v souboru test.bdf, což nejsnáze provedeme, když

test.bdf otevřeme v grafickém editoru, pravou myší vyvoláme kontextové menu symbolu majority.

Volíme "Update symbol or Block…". Aktualizaci schématu můžeme samozřejmě alternativně provést

i tím, že starý symbol smažeme a na jeho místo vložíme nový.

Obrázek 6 - Aktualizace změněného symbolu

c) Do aktualizovaného schématu přidáme výstup na port y1 pojmenovaný třeba LEDR[1]

d) Nakonec přeložíme test.bdf úplným překladem a nahrajeme výsledek do desky DE2.

Page 15: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

15

Obrázek 7 - Výsledné schéma v test.bdf

1-2.e) Co když potřebujeme nerozšířenou verzi majority?

Dvě různé majority s odlišnými výstupy v jednom projektu by si žádaly i odlišné názvy souborů

a jejich entit. V našem případě jsme upřednostnili jen jeden název, tj. nechali si jen rozšířený obvod. Bu-

deme-li někdy potřebovat obyčejnou majoritu, tj. bez rozšíření o výstup y1 aktivace právě jednoho signá-

lu, tak y1 jednoduše nepoužijeme, tj. k ničemu ho nepřipojíme, viz obrázek dole:

Z protokolu překladače (Quartus okno "Compilation Report") plynou následující skutečnosti:

Rozšířená majorita, Obrázek 7, se všemi zapojenými výstupy má složitost 2 LE, tedy dva logické

elementy použitého FPGA.

Zapojení, u něhož není zapojený výstup y1, Obrázek 8, má složitost 1 LE, tedy stejnou složitost jako

původní nerozšířená majorita, viz Obrázek 1 na straně 5. Nezapojené rozšíření si překladač Quartus II

automaticky vystřihl.

Liší-li se obvody jen v přidaném rozšíření a zachovávají přitom svoji původní funkčnost, pak nemusíme

nutně mít několik verzí pod různými názvy, ale stačí nám jen jeden univerzální obvod.

VCCSW[0] INPUT

VCCSW[1] INPUT

VCCSW[2] INPUT

LEDR[0]OUTPUT

LEDR[1]OUTPUT

a

b

c

y

y 1

majorita

inst

Obrázek 8 - Rozšířená majorita s nezapojeným výstupem y1

VCC SW[0] INPUT

VCC SW[1] INPUT

VCC SW[2] INPUT

LEDR[0] OUTPUT a b c

y

majorita

inst

y1

Page 16: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

16

1-3 Dekodér pro ukazatel — příkazy with…select jazyka VHDL Zadání:

Navrhněte dekodér pro lineární ukazatel hodnoty.

V jeho tříbitovém výstupu bude tolik bitů v logické ´1´,

kolik má adresa hodnotu, jak ukazuje pravdivostní ta-

bulka vpravo.

Pravdivostní tabulka dekodéru

Vstup adresy Výstupy

Hodnota A1 A0 Q2 Q1 Q0

0 0 0 0 0 0

1 0 1 0 0 1

2 1 0 0 1 1

3 1 1 1 1 1

Řešení:

Můžeme snadno napsat tři logické rovnice, pro každý výstup jednu. Podobný postup není však uni-

verzální a ani přehledný. Nehodil se pro delší ukazatele hodnoty, např. u dekodéru se čtyřbitovou adresou

by měl patnáct výstupů a potřeboval by 15 rovnic. Hledáme jiné, mnohem přehlednější řešení.

Vhodné řešení nabízí přepínač. Poloha jeho jezdce je určena adresou a na kontakty jsou připojené

požadované výstupní kombinace hodnot bitů. K přepínači existuje analogie v podobě multiplexoru pro-

pouštějícímu na výstup jen hodnotu ze vstupu vybraného adresou.

Ve VHDL se multiplexor definuje příkazovou konstrukcí with...select.

Řešení ve VHDL:

Opět uvedeme napřed celý VHDL kód a pak rozebereme jeho zajímavé části odděleně.

-- Dekoder pro linearni ukazatel -- 1 library ieee; use ieee.std_logic_1164.all; -- 2 -- 3 entity dekoder2linearni is -- 4 port -- 5 ( A : in std_logic_vector(1 downto 0); -- 6 Q : out std_logic_vector(2 downto 0) -- 7 ); -- 8 end; -- 9 -- 10

architecture dataflow of dekoder2linearni is -- 11 begin -- 12 with A select -- 13 Q <= "000" when "00", -- 14 "001" when "01", -- 15 "011" when "10", -- 16 "111" when others; -- 17 end; -- 18

Program 4 - Dekodér pro lineární ukazatel

1-3.a) Příkaz with…select

Vstup A i výstup Q jsou definované jako vektory, kterým v obvodech odpovídají sběrnice neboli

skupiny číslovaných vodičů — A má dva vodiče A(1) a A(0); Q tři vodiče Q(2), Q(1) a Q(0). Začátek pří-

kazu with A select specifikuje adresní vstup multiplexoru. Do Q se přiřazují hodnoty vybrané A. Jejich

mapování určí konstanta za klíčovým slovem when rovná hodnotě vstupu adresy. Musí se vždy vyčerpat

všechny možnosti — přepínač (multiplexor) pokaždé vrací nějakou hodnotu. Kvůli tomu poslední volba

obsahuje klíčové slovo others, což znamená všechny dosud neuvedených možností.

1

0

3

2

A1 A0

Q2Q1Q0

"000"

"001"

"011"

"111"

Q2Q1Q0

A1 A0

"000"

"001"

"011"

"111"

Page 17: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

17

1-3.b) Datový typ std_logic versus std_logic_vector

Proměnné typu std_logic představují výčtový typ, jehož hodnoty byly uvedené na straně 9. Bu-

deme-li mít definici signal t, x, y, z :std_logic;, pak do těchto proměnných můžeme přiřadit logický výraz

nebo konstanty jeho výčtového typu, např.

t<=´Z´; x<=´1´; y<=´0´; z <= x AND y; Konstanty ´1´ a ´0´ jsou v uvozovkách, nejde o čísla, ale o hodnoty z definice std_logic výčtového typu

v knihovně ieee.std_logic_1164 seznamem hodnot, tj. analogicky k typům enum v Java či C#:

type std_logic is ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-');

Datový typ std_logic_vector představuje naproti tomu jednorozměrné polem složené z prvků

datového typu std_logic a standardní knihovna ieee.std_logic_1164 ho definuje jako

type std_logic_vector is array (natural range<>) of std_logic ;

kde

type je klíčové slovo definice typu a std_logic_vector název vytvořeného typu;

natural znamená datový subtyp specifikující číslo typu integer omezené na rozsah 0 až ma-

ximální celé číslo definované v typu integer; (to můžeme zjistit atributem integer´HIGH, viz dá-

le na str. 18 ). Knihovna ieee definuje 32bitvové integer, tj. v rozsahu od -2-31

do 231

-1;

range je klíčové slovo specifikující interval. Ve spojení s natural určuje interval popsaný ce-

lými čísly od 0 do maximálního čísla integer .

range < > znamená nespecifikovaný rozsah, jeho hodnota bude doplněna při použití typu.

Budeme-li mít v architektuře například definice: pak jim odpovídá následující uspořádání:

signal A, B, C: std_logic_vector (7 downto 0);

signal Z: std_logic_vector (1 to 16)

Interval (range) u A, B a C směřuje od 7 do 0, tj. odshora dolů, tedy shodně s číslováním bitů v bi-

nárních číslech, což se upřednostňuje. Směr "to" se používá zpravidla jen pro interní proměnné.

Konstanty typu std_logic jsou v ´ ´ apostrofech, zatímco u typu std_logic_vector jsou v " " uvozov-

kách, a to i v případě, když vektor má délku jen jeden člen. Vektorům totiž odpovídají řetězce. Dlouhé

řetězce, pokud mají počet členů rovný přesně mocnině 2, můžeme zkráceně zapsat hexadecimálním řetěz-

cem, v němž je znak X před první uvozovkou.

Vše nejlépe přiblíží příklad použití výše uvedených proměnných:

A<="10101100"; B<=X"5F"; C<=A AND B; Z(2 to 9)<=C; Z(14 to 15)<= C(4 downto 3);

Obrázek 9 - Operace s std_logic_vector

POZOR, proměnné polí (vektorů) se musí pořád používat se směrem číslování určeným v jejich definici,

tj. s downto nebo s to. Směr se nesmí nikdy obrátit. Napíšeme-li Z(15 downto 14), překladač ohlásí chy-

bu obsahující text: "…range direction of object slice must be same as range direction of object…".

A, B a C:

Z: 1 2 3 4 5 6 7 8 9

7 6 5 4 3 2 1 0

10 11 12 13 14 15 16

preferované

pořadí downto

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Z

7 6 5 4 3 2 1 0

1 0 0 0 1 1 0 0A

7 6 5 4 3 2 1 0

0 1 0 1 1 1 1 1B

7 6 5 4 3 2 1 0

0 0 0 0 1 1 0 0C

0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0

Z(2 to 9)<=C;

C<=A and B;

A<="10001100";

B<=X"5F";

Z(14 to 15)<=C(4 downto 3);

Page 18: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

18

Z vektoru (pole) můžeme zvolit jeden člen nebo několik prvků, tedy podvektor. Napíšeme-li definice:

signal A: std_logic_vector (7 downto 0); signal xv1, yv1: std_logic_vector (0 downto 0);

signal x, y: std_logic;

pak můžeme použít následující příkazy:

x <= A(0); A(0) vybere z pole prvek na indexu 0, ten bude datového typu std_logic.

A(1) <= '0'; Inicializace prvku datového typu std_logic v poli A na indexu 1.

yv1 <= "0"; Inicializace vektoru std_logic_vector , který má délku 1 člen.

xv1 <= A(2 downto 2); Z vektoru A se vybere vektor datového typu std_logic_vector o délce 1 člen;

ten bude rovný prvku na indexu 2 vektoru A.

Pozn. Editor schémat (*.bdf) v Quartus II používá pro rozsahy polí stručné zápisy stylu Pascal. Schématu

s popisy signálů A[2..0], Z[1..7] a A[1] odpovídají ve VHDL zápisy: A(2 downto 0), Z(1 to 7) a A(1).

1-3.c) Tvorba vlastních typů a atributy VHDL

VHDL je typově velmi striktní. Definujeme-li si dva vlastní typy se shodnou strukturou, budou

z hlediska překladače různé. Mějme například:

type std_logic_vector_A is array (7 downto 0) of std_logic; type std_logic_vector_B is array (7 downto 0) of std_logic; signal s lvA1, s lvA2 : std_logic_vector_A ;

signal s lvB1, slvB2 : std_logic_vector_B ;

Inicializace proběhne v pořádku; ta pracuje s členy vektorů a ty jsou shodného datového typu std_logic.

slvA1 <= X"12"; slvB1 <= X"34"; -- OK, lze

Pokud se pokusíme vzájemně přiřadit proměnné obou skupin, nepůjde to:

slvB2<=slvA1; slvA2<=slvB1; -- Chyba při překladu - typy nesouhlasi

U silně typových jazyků, mezi které patří i VHDL, se shoda struktury datového typu netestuje, důležitá

jsou výhradně jména typů, a ta se liší. Existuje však možnost definovat si subtyp zužující originální typ.

Přepíšeme-li výše uvedené definice na subtypy:

subtype std_logic_vector_A is std_logic_vector (7 downto 0); subtype std_logic_vector_B is std_logic_vector (7 downto 0);

signal slvA1, slvA2 : std_logic_vector_A ;

signal slvB1, slvB2 : std_logic_vector_B ;

pak se příkazy předchozího programu přeloží bez chyby. Subtypy se pokládají za plně kompatibilní s vý-

chozím datovým typem a všemi jeho subtypy:

slvA1 <= X"12"; slvB1 <= X"34"; slvB2<=slvA1; slvA2<=slvB1;

U neznámých typů se lze dotazovat na parametry jejich definic pomocí vlastností nazývaných ve

VHDL atributy, které mají stejné užití jako "property" známé z tříd v Java či v C#, jen se neoddělují teč-

kou, ale apostrofem. Pro typy odvozené od std_logic_vector se hodí následující atributy:

Příklad použití Integer hodnota výsledku Popis

slvA1´left 7 levá hodnota indexu rozsahu

slvA1´right 0 pravá hodnota indexu rozsahu

slvA1´low 0 nižní číselná hodnota indexu rozsahu

slvA1´high 7 vyšší číselná hodnota indexu rozsahu

slvA1´length 8 počet prvku Tabulka 4 - Vybrané atributy

V definicích nových proměnných či v příkazech lze použít také atributy rozsahu:

signal X : std_logic_vector(31 downto 0);

signal novy1 : std_logic_vector(X'range); -- (31 downto 0)

signal novy2 : std_logic_vector(X'reverse_range); -- (0 to 31)

Page 19: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

19

1-3.d) Dekodér pro lineární ukazatel s výstupy na jednotlivé vodiče

Může se stát, že předchozí dekodér

nevyhovuje a chceme jiný, kde vstupy a

výstupy nejsou sběrnice, ale jednotlivé

vodiče, jak ukazuje požadované schéma.

Můžeme využít velkou část před-

chozího kódu, ve kterém provedeme

drobné změny, v programu dole vyzna-

čené zvýrazněním:

--Dekoder pro linearni ukazatel s oddelenymi vystupy -- 1

library ieee; use ieee.std_logic_1164.all; -- 2 -- 3 entity dekoder2linearniB is -- 4 port -- 5 ( A1, A0 : in std_logic; -- 6 Q2, Q1, Q0 : out std_logic -- 7 ); -- 8 end; -- 9 -- 10 architecture dataflow of dekoder2linearniB is -- 11 signal A : std_logic_vector(1 downto 0); -- 12 signal Q : std_logic_vector(2 downto 0); -- 13 begin -- 14 A <= A1 & A0; -- 15 with A select -- 16 Q <= "000" when "00", -- 17 "001" when "01", -- 18 "011" when "10", -- 19 "111" when others; -- 20 Q2<=Q(2); Q1<=Q(1); Q0 <= Q(0); -- 21 end; -- 22

Program 5 - Dekodér pro ukazatel s oddělenými výstupy

Postup:

a) Napřed jsme program uložili jako zcela nový soubor pod názvem dekoder2linearniB.vhd a blok entity

přejmenovali na dekoder2linearniB, abychom mohli v projektu stále používat obě entity.

b) Původní definice vstupů a výstupů v sekci port jsme přesunuli do architektury a udělali z nich signály,

řádky 12 a 13, abychom mohli použít stávající kód, který se na ně odvolává.

c) Do bloku port jsme vložili nové definice vstupů a výstupů jako jednotlivých signálů, řádky 6 a 7.

d) Vektorový signál A jsme naplnili hodnotami vstupů A1 a A0 pomocí operátoru & jejich spojení do

vektorové proměnné typu std_logic_vector, řádka 15. Lze samozřejmě použít i příkazy A(1)<=A1;

A(0)<=A0; , ale operátor & je stručnějším zápisem.

e) Výstupy žel musíme rozdělit po jednotlivých prvcích vektoru na řádce 21. Zde neexistuje žádná

zkratka — operátor & nemůže stát jen na levé straně <= přiřazení. Pozn. V obvodech se spíše snažíme

vodiče sjednocovat do vektorů (sběrnic), aby se s nimi lépe a rychleji pracovalo než z nich udělat

mnoho samostatných drátků.

f) Vygenerujeme-li symbolu dekoder2linearniB a vložíme-li ho do schématu, můžeme obvod vyzkoušet.

Nevýhoda naší úpravy spočívá v duplicitě — kód pro lineární ukazatel máme nyní nakopírovaný do

dvou entit. Bude-li potřeba opravit jednu kopii, nesmíme zapomenout provést změnu i ve druhé. V části

o strukturálním popisu si ukážeme jinou metodu, a to jednodušší a mnohem bezpečnější.

VCC SW[1] INPUT

VCC SW[0] INPUT LEDR[1] OUTPUT LEDR[2] OUTPUT

LEDR[0] OUTPUT

A1 A0

Q2 Q1 Q0

dekoder2linearniB

inst

Obrázek 10 - Dekodér pro lineární ukazatel s bitovými I/O

Page 20: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

20

1-4 Prioritní dekodér — VHDL příkaz when…else Zadání:

Pro tři vstupy žádostí o přerušení procesoru Int3

až Int1 navrhněte prioritní dekodér, který posílá na

sběrnici číslo periférie žádající o přerušení. Při aktivním

vstupu Int3 s nejvyšší prioritou bude na výstupu číslo 3,

ostatní vstupy se ignorují. Int1 má nejnižší prioritu

a posílá číslo 1, jsou-li zbývající vstupy v ´0´. Nežádá-li

nikdo se o přerušení, výstup bude číslo 0, viz zkrácená

pravdivostní tabulka.

Prioritní dekodér

Vstupy Výstupy

Int3 Int2 Int1 Q1 Q0 Číslo

1 - - 1 1 3

0 1 - 1 0 2

0 0 1 0 1 1

0 0 0 0 0 0

Řešení:

Mohli bychom samozřejmě sestavit logické rovnice, což by lehce šlo u takhle malého obvodu, ale

takový postup se nedá snadno rozšířit například na případ pro 15 vstupů se čtyřbitovým výstupem. Opět

budeme hledat univerzálnější řešení.

Minule jsme si pomohli přepínačem, zde

se ho uplatníme také, ale nikoliv jako jeden

přepínač s mnoha pozicemi. Použijeme několik

dvoupólových přepínačů řazených do kaskády,

čím přirozeně vytvoříme prioritu.

Bude-li sepnutý první přepínač Int3, pak

na výstup Q1 Q0 bude přivedena kombinace

"11", tj. číslo 3, bez ohledu na pozice ostatních

přepínačů. Nebude-li sepnutý Int3, teprve pak

se uplatní další přepínače dle pořadí (priority).

Ve schématu přepínače nahradíme multi-

plexory dvou sběrnic o šířce dva bity; ty ozna-

čují dvojité čáry. Multiplexory budou řazené za

sebou stejně jako přepínače a jejich jednobitové

adresní vstupy budou vstupy přerušení INT[x],

a to v pořadí jejich požadované priority.

Podobné konstrukci odpovídá ve VHDL podmíněné přiřazeni when …else. Po jeho vložení do-

staneme kód:

--Prioritni dekoder -- 1 library ieee; use ieee.std_logic_1164.all; -- 2 -- 3

entity prioritni_dekoder is -- 4 port ( INT : in std_logic_vector(3 downto 1); -- 5 Q : out std_logic_vector(1 downto 0) ); -- 6 end; -- 7 architecture dataflow of prioritni_dekoder is -- 8 begin -- 9 Q<= "11" when INT(3)='1' else -- 10 "10" when INT(2)='1' else -- 11 "01" when INT(1)='1' else -- 12 "00"; -- 13 end; -- 14

Program 6 - Prioritní dekodér

Chování příkazu when .. else, řádky 10 až 13, vyplývá z jeho implementace pomocí kaskády

dvouvstupových multiplexorů dvoubitových sběrnic. Pokud bude nějaká podmínka splněna, její multi-

plexor se přepne a stav všech dalších multiplexorů ležící za ním, nemá již vliv na výsledek. Kvůli tomu

"01"

Int2=0

"10" Q1Q0

Int3=1

"11"

"00"

1

1

1

Int1=1

0

"11"

"01"

Int2=0

"10" Q1Q0

Int3=0

"11"

"00"

1

1

1

Int1=0 0

0

"00"

0

1

0

1

0

1

0

"11"

"01"

"00"

"10"

INT[3]

INT[2] INT[1]

0

Q[1..0]

Obrázek 11 - Prioritní dekodér z multiplexorů

Page 21: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

21

v dalších podmínkách ležících níže již nemusíme opakovat případné nesplnění předchozích podmínek.

Bylo by zbytečné a matoucí mít na řádcích 10 až 13 v Program 6 něco takového jako:

Q<= "11" when INT(3)='1' else -- 10 "10" when INT(3)='0' and INT(2)='1' else -- 11 "01" when INT(3)='0' and INT(2)='0' and INT(1)='1' else -- 12 "00"; -- 13

Program 7 - Zbytečné podmínky v příkazu when...else

Pokud by někdo napsal příkaz takhle, nedopustil by se chyby, ale jen by zbytečnými testy opomíjel prio-

ritní strukturu příkazu when…else, viz podtržené části. Např. hodnota na řádku 11 se použije jen při

nesplnění podmínky na řádku 10; tak proč zde testovat INT(3)='0'? Kód ztrácí na přehlednosti vnuco-

váním zbytečné otázky: "Kvůli čemu je tam tohle? — Aha, už vím; jen mňamka pro klávesu delete!"

1-4.a) Operátory porovnání a logické operátory ve VHDL

Priorita Datový typ výsledku Operátory

Nejvyšší stejný jako operandy*) not

Boolean (true, false) = /= < <= > >= Nejnižší stejný jako operandy*) and or nand nor xor xnor

*) Logické operátory jsou v ieee.std_logic_1164 definované jak pro typ std_logic , kdy vracejí výsle-

dek typu std_logic, tak pro std_logic_vector kde dávají výsledek typu std_logic_vector, a také

pro typ Boolean; zde je jejich výsledkem opět Boolean. Tabulka 5 - Porovnávací operátory a logické operátory

Porovnávací operátory mají obvyklou syntaxi, až méně běžný zápis /= pro nerovnost, a prioritně le-

ží mezi operátorem not a ostatními logickými operátory. U složitějších výrazů se proto vyplatí používat

závorky, aby se not aplikovalo správně. Datový typ Boolean, který vracejí porovnávací operátory, se dá

použít jedině jako parametr podmínky; z příkazů s podmínkami zatím známe jen when..else.

Opakované podmínky lze případně uložit do proměnné typu Boolean — ta nebude ale přiřaditelná

do typů std_logic; zde nutno použít konstrukci when..else, viz řádky 11 a 17 dole.

--Prioritni dekoder -- 1 library ieee; use ieee.std_logic_1164.all; -- 2 entity prioritni_dekoder is -- 3 port ( INT : in std_logic_vector(3 downto 1); -- 4 Q : out std_logic_vector(1 downto 0); -- 5 NoInt : out std_logic ); -- 6 end; -- 7 architecture dataflow of prioritni_dekoder is -- 8 signal jeInt3, zadnyInt :Boolean; -- 9 begin -- 10 jeInt3 <= INT(3)='1'; -- 11 Q<= "11" when jeInt3 else -- 12 "10" when INT(2)='1' else -- 13 "01" when INT(1)='1' else -- 14 "00"; -- 15 zadnyInt <= not jeInt3 and INT(2)='0' and INT(1)='0'; -- 16 NoInt <= '0' when zadnyInt else '1'; -- 17 end; -- 18 Program 8 - Program pro demonstraci práce s proměnnými datového typu Boolean

Konstrukce na řádcích 16 a 17 je samozřejmě krajně krkolomná a slouží pouze jako demonstrativní

ukázka práce s podmínkami. Dala by se samozřejmě nahradit:

NoInt <= not INT(3) and not INT(2) and not INT(1);

Pozn. Jako podmínku nelze použít samotný logický výraz proměnných typu std_logic, např. napsat

v programu nahoře na řádku 13 … when INT(2) else…; protože INT(2) není datového typu Boolean; ten

nám vrátí až operátor porovnání. Musíme psát …when INT(2)='1' else….

Page 22: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

22

1-4.b) Pohled do nitra překladače přes RTL Viewer

Tato podkapitola probírá mírně pokročilejší témata. Začátečníkům ji doporučuji přeskočit a vrátit se

k ní později. Není zde uvedeno cokoliv, na co by se navazovalo v dalším textu.

Prioritní dekodér jsme si začali tvořit jako schéma z multiplexorů, viz Obrázek 11 na straně 20. Bu-

de ho překladač skutečně tak i implementovat? Poví nám to meziprodukty překladu; ty uvidíme až po

přeložení top-level entity programu. Za tu vybereme buď 1/ soubor prioritni_dekoder.vhd, nebo 2/ schéma,

do kterého jsme vložili prioritni_dekoder. Při způsobu 1/ najedeme myší na priority_dekoder v bloku entity,

pravou myší vyvoláme kontextové menu, z něhož zvolíme Locate->Locate in RTL Viewer. Zvolili-li jsme

cestu 2, vybereme ve schématu vloženou instanci a pravou myší vyvoláme její kontextové menu, kde

provedeme stejnou volbu a poté ješte levou myší otevřeme zobrazený blok instance prioritni_dekoder.

Obrázek 12 - Vyvolání RTL Viewer z top-level entity

Ukáže se "RTL Viewer" (Register Transfer Logic

Viewer) schéma ukazující, jak překladač pochopil

náš program a jaký jeho model si sestavil po mini-

malizaci — opravdu použil kaskádu, ale jen ze

dvou multiplexorů, ne tří jako na schématu

"Obrázek 11" na straně 20. Vytvořeno v Quartus II verze 13.0sp1

Vyvoláváním nápověd u vodičů (najetím na ně myší), zjistíme, že schéma je zapojeno zjednodušeně. Na

obrázku dole vlevo je překreslené RTL vnitřní schéma překladače a vpravo část hypotetického VHDL pro-

gramu, který by mu logicky odpovídal.

architecture dataflow_RTL_Viewer of prioritni_dekoder is begin Q(1)<= '1' when INT(3)='1' else INT(2); Q(0)<= '1' when INT(3)='1' else '0' when INT(2)='1' else INT(1); end;

Program 9 - Minimalizovaná kaskáda multiplexorů

Pokud se dobře podíváme na Obrázek 11 na straně 20, uvidíme, že překladač má pravdu. Levý multi-

plexor lze nahradit ´0´ & INT(1) — posílá "01" při INT1(1), jinak "00". Postřední multiplexor se zase dá

zmenšit na jednobitový. Nicméně určitě můžeme označit za přehlednější úplný příkaz when…else v "Program 6 - Prioritní dekodér" na straně 20 než jeho super-minimalizovanou verzi v Program 9.

I ve VHDL platí zásada, že programy píšeme především přehledně a srozumitelně. V drtivé vět-

šině případů můžeme dokonalé minimalizace nechat překladači — umí je lépe a taky rychleji než my .

Q[0]

Q[1] ´1´

INT[1]

INT[2]

´1´ 1bitový

2bitový

INT[3]

1

0

1

0

1

0

´0´

Page 23: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

23

1-5 Tříbitový prioritní inhibitor — cyklus for-generate Zadání: Navrhněte obvod s osmnácti vstupy A[17..0] a výstupy Q[17..0] propouštějící pouze nej-

vyšší vstup ve stavu ´1´ na jemu číselně odpovídající výstup, takže nejvýše jen jeden výstup je v ´1´ —

kvůli tomu jsme obvod nazvali prioritní inhibitor. Pozn. Osmnáct vstupů a výstupů volíme kvůli desce

DE2, která obsahuje osmnáct přepínačů SW a červených led diod LEDR.

Kde bychom takový obvod použili? Představte si, že máte 18 přepínačů ovládajících nějaké funkce,

přičemž se žádá, aby se najednou zapnul jen jeden přepínač. Uživatel může nechtěně, či úmyslně ("poku-

šitel jeden"), provést i několik voleb najednou. Pokud se za přepínače zapojí náš prioritní inhibitor, dupli-

citní zapnutí se potlačí podle priorit přepínačů a máme jistotu volby jen jedné funkce.

Řešení: Příklad představuje prioritní úlohu a šel by řešit pomocí kaskády multiplexorů, stejně jako před-

chozí prioritní dekodér, tedy pomocí konstrukce when…else. Nedal by se ale lehce modifikovat pro jinou

délku vektorů bez dlouhavého přepisování. Zkusíme najít elegantnější řešení.

Napřed si napíšeme logickou tabulku pro dekodér se třemi vstupy a třemi výstupy, abychom zjistili,

zda v ní najdeme možné zákonitosti:

Úplná pravdivostní tabulka

Vstupy Výstupy

A2 A1 A0 Q2 Q1 Q0

0 0 0 0 0 0

0 0 1 0 0 1

0 1 0 0 1 0

0 1 1 0 1 0

1 0 0 1 0 0

1 0 1 1 0 0

1 1 0 1 0 0

1 1 1 1 0 0

Zkrácená pravdivostní tabulka

Vstupy Výstupy

A2 A1 A0 Q2 Q1 Q0

0 0 0 0 0 0

0 0 1 0 0 1

0 1 - 0 1 0

1 - - 1 0 0

Z pravdivostní tabulky, a to především z její zkrácené verze, vidíme, že

Výstup Q2 je evidentně kopií A2, čili Q2 = A2.

Q1 bude v ´1´ jedině tehdy, pokud A2=´0´ a A1=´1´, což lze napsat rovnicí: Q1 = not A2 and A1.

Výstup Q0 bude v ´1´ pouze při vstupech A2=´0´, A1=´0´ a A0=´1´, což zapíšeme logickou rovnicí

Q0 = not A2 and not A1 and A0.

Vidíme, že výstup Qi bude v ´1´ jedině tehdy, když všechny odpovídající vyšší bity A (tj. Aj pro j>i) jsou

v ´0´. Označíme-li N počet bitů a názvem enable pole N proměnných, můžeme napsat rekurzivní vztah:

QN-1 := AN-1; enableN-1 := not AN-1;

Qi := enable i+1 and Ai; enablei := enable i+1 and not Ai; pro i = N-2 až 0

Proč jsme místo jedné proměnné enable použili pole? Program budeme přepisovat do VHDL, kde signá-

lům můžeme hodnotu přiřadit maximálně jen jednou, a tak jsme rekurzivní vztah záměrně vytvořili tak,

aby respektoval podmínku jednoho zápisu do proměnné.

Správnost našeho rekurzivního vztahu si můžete vyzkoušet třeba v Java metodě třídy:

public void PriotritniInhibitor(boolean A[], boolean Q[]) //1

{ boolean[] enable = new boolean[Q.length]; //2

if (A.length != Q.length || A.length < 2) //3

throw new IllegalArgumentException("Obe pole musi mit stejnou delku>1"); //4

Q[Q.length - 1] = A[Q.length - 1]; enable[Q.length-1] = ! (A[Q.length - 1]); //5

for (int i = Q.length - 2; i >= 0; i--) //6

{ Q[i] = enable[i+1] && A[i]; enable[i] = enable[i+1] && !A[i]; //7

} //8

} //9

} //10 Program 10 - Java metoda pro vyzkoušení prioritního inhibitoru

Page 24: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

24

Pole proměnných Java typu boolean nahradíme doporučeným typem std_logic_vector s číslování

odshora dolů (downto).

Cyklům for bude v hardwaru odpovídat opakování příkazů. Podobným způsobem se někdy i optima-

lizuje kód na rychlost; kratší cykly se nahradí rozbalením jejich příkazů. Například, mělo-li by pole Q

z Java kódu Program 10 délku 3 prvky, tj. Q.length = 3, pak cyklus bude:

for (int i = 2; i >= 0; i--) //6 { Q[i] = enable[i+1] && A[i]; enable[i] = enable[i+1] && !A[i]; } //7

a při jeho optimalizaci na rychlost by se nahradil sérií příkazů:

Q[2] = enable[3] && A[2]; enable[2] = enable[3] && !A[2]; //7-i=2 Q[1] = enable[2] && A[1]; enable[1] = enable[2] && !A[1]; //7-i=1 Q[0] = enable[1] && A[0]; enable[0] = enable[1] && !A[0]; //7-i=1

Výsledek má sice větší délku, ale ušetřilo se načítání a testování parametru cyklu a výpočty adres polí;

jejich indexy jsou teď konstanty. Podobnou expanzi provede i VHDL pomocí generace. Výsledkem

bude VHDL kód:

-Prioritni inhinitor -- 1

library ieee; use ieee.std_logic_1164.all; -- 2 entity prioritni_inhibitor is -- 3 port ( A : in std_logic_vector(17 downto 0); -- 4 Q : out std_logic_vector(17 downto 0) ); -- 5 end; -- 6 architecture dataflow of prioritni_inhibitor is -- 7 signal enable: std_logic_vector(Q'range); -- 8 begin -- 9 Q(Q'LENGTH-1)<=A(Q'LENGTH-1); -- 10 enable(Q'LENGTH-1)<= not A(Q'LENGTH-1); -- 11

cyklus : for i in Q'LENGTH-2 downto 0 generate -- 12

Q(i)<=enable(i+1) and A(i); -- 13 enable(i)<= enable(i+1) and not A(i); -- 14 end generate; -- 15 end; -- 16

Program 11 - Prioritní inhibitor pro 18 vstupů a výstupů

Generační cyklus začíná na řádku 12. Jeho obecná syntaxe je

label : for <parameter> in <range> generate <concurrent-statements>

end generate [label] ;

kde

label je povinné návěští oddělené dvojtečkou. Musíme ho zadat, i když ho nikde dál již nepouži-

jeme. Zvolili jsme název "cyklus", ale mohli i jiný, třeba "opakuj" apod.

<parameter> představuje parametr cyklu, který bude nabývat hodnot v rozsahu <range>;

<range> udává rozsah hodnot; ten má stejný tvar jako rozsahy polí, je buď downto nebo to ;

end generate [label] ; — cyklus se musí zakončit buď end generate nebo end generate label;

Klíčové slovo generate je povinné, zde ho nelze vynechat;

<concurrent-statements> označuje blok příkazů řazených mezi "concurrent", tj. probíhajících

paralelně. Sem patří přiřazení <= a konstrukce with..select , when..else, dále také for-generate

(cykly lze vnořit) a lze použít i podmíněnou generaci if-generate a příkaz port map; ten probere-

me ve strukturálním stylu VHDL. Příkazy musí být vždy úplné; nelze tedy vkládat jen jejich dílčí

části, jako třeba jednotlivé řádky podmínek ve "when..else" či přidávat členy do výrazů.

Pozn. Příkaz for-generate lze použít jedině v architektuře, v entitě ne. Dále může i své mít lokální pro-

měnné. Zájemci najdou podrobnější informace na webu ve VHDL referenčních příručkách.

Page 25: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

25

1-5.a) Jak vložit do výjimky do VHDL — příkazy generic a assert

Java metoda Program 10 na str. 23, ve které jsme testovali rekurzivní vztah pro prioritní inhibitor,

obsahovala příkaz "throw" pro metání výjimky v kódu. Ve VHDL programu jsme nic takového nepoužili;

nemuseli jsme, vektory měly zatím pevné délky. Lze však mít i pole variabilní délky určené externím

generic parametrem, který se zadává zvnějšku, a tak každá instance obvodu může jeho hodnotu mít od-

lišnou. Parametr definujeme v bloku entity , viz řádek 4 dole:

- -Pr ior itn i inhin itor -- 1 l ibrary ieee; use ieee.std_log ic_1164. a l l ; -- 2

entity prioritni_ inhibitor is -- 3 generic( N: natural := 18); -- delka vektoru > 1 -- 4 port ( A : in std_logic_vector(N-1 downto 0); -- 5 Q : out std_logic_vector(N-1 downto 0)); -- 6 end; -- 7 architecture dataflow of prior itni_ inhibitor is -- 8 s ignal enable: std_logic_vector(Q'range); -- 9 begin -- 10 assert N>1 report "Chybny parametr N. Pozadovano N>1" -- 11 severity fai lure; -- 12 Q(Q'LENGTH-1)<=A(Q'LENGTH-1); -- 13 enable(Q'LENGTH-1)<= not A(Q'LENGTH-1); -- 14 cyklus : for i in Q'LENGTH-2 downto 0 generate -- 15 Q(i)<=enable( i+1) and A(i) ; -- 16 enable(i)<= enable(i+1) and not A( i) ; -- 17 end generate; -- 18 end; -- 19

Program 12 - Prioritní inhibitor s generic

Definice generic může obsahovat i několik různých parametrů:

generic( name1: type1 := default_value1; name2: type2 := default_value2;

. . .

nameN: typeN := default_valueN );

Zadané parametry se v programu vždy chovají jako konstanty. Quartus II u nich požaduje výchozí hodno-

tu, která se přiřazuje pomocí := , nikoliv <= "concurrent assignment", protože nejde o propojení; všech-

ny parametry se v době překladu nahradí hodnotami uvedenými v jejich instancích entity.

Konstantu N jsme v našem programu použili u definic rozsahu vstupů a výstupů. Zbytek kódu jsme

nemuseli přepisovat, jelikož jsme "prozíravě" použili atributy, což je obecně doporučovaný postup.

Obrázek 14 - Ukázka použití prioritního inhibitoru ve schématu

Pozn. 1/ Všimněte si, že stejně jako u bloku port se ani v generic nepíše ; za poslední prvkem seznamu.

2/ V editoru schémat lze zapnout/vypnout zobrazování hodnot parametrů u instancí v kontextovém menu

editoru (pravou myší kamkoliv na volnou plochu a "Show->Show Parameter Assignments").

VCCSW[17..0] INPUT LEDR[17..0]OUTPUT

N 18 Signed Integer

Parameter Value Type

A[n-1..0] Q[n-1..0]

prioritni_inhibitor

inst

Obrázek 13 - Příklad použití prioritního inhibitoru

VCC SW[17..0] INPUT LEDR[17..0] OUTPUT A[17..1] Q[17..0]

prioritni_inhibitor

inst

Page 26: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

26

Příkaz assert použitý v programu na řádcích 11 a 12 není přesnou analogií výjimky throw v Java, proto-

že se nevyvolává při činnosti obvodu; to by ani nešlo. Při syntéze obvodu se vyhodnocuje už v době pře-

kladu a odpovídá stejnojmenným příkazům či metodám realizovaným různými formami i v Java, C#

a C++. Ve VHDL má příkaz assert syntaxi:

assert <condition> report <string> severity <severity_level>;

kde

<condition> je jakýkoliv výraz vracející datový typ Boolean ;

<string> označuje řetězec, který překladač vypíše uživateli, pokud nebude podmínka splněná, tj. při

podmínce s hodnotou false;

<severity_level> specifikuje požadovanou reakci překladače, ta je buď note, warning, error, failure,

note — text se vypíše mezi informacemi;

warning — vypíše se varováními a bude se pokračovat v sestavování obvodu;

error — udává chybu zcela bránící v sestavení obvodu;

failure — znamená inkonsistenci, nesmyslné zadání, které by nikdy nemělo nastat.

Pozn. V příkazu assert lze vynechat část "severity <severity_level>" , poté se pro <severity_level> automaticky zvolí výchozí hodnota error.

Příklad vypsaných chyb při nedovolené hodnotě parametru ve schématu dole [Quartus II 13.0sp1]:

Error (10652): VHDL Assertion Statement at prioritni_inhibitor.vhd(11): assertion is false -

report "Parametr N musi byt vetsi jak 1" (FAILURE or ERROR)

Error (12152): Can't elaborate user hierarchy "prioritni_inhibitor:inst"

V hlášení se uvádí odkaz "prioritni_inhibitor.vhd(11)" na soubor prioritni_inhibitor.vhd řádek 11, kde se

nachází příkaz assert , u něhož se nesplnila požadovaná podmínka.

1-5.b) Co programu ještě chybí?

Poslední program se již blíží skutečným VHDL programům pro svou vysokou univerzalitu. Můžeme ho

beze změny aplikovat na různé šířky sběrnic, ale přesto není příliš dobrý.

Chybí zde především komentáře, jak jsme již uvedli zde úmyslně vynechané pro zkrácení řádek. Při

nejmenším by se v dobrém programu měly pečlivě komentovat definice v bloku entity a hlavních

proměnných, aby se nemusel luštit jejich význam. Hodí se i vkládat komentářové řádky před celky

kódu specifikující, co se v nich vlastně provádí. Pozn. Hodně programátorů časem zjistí, že komentá-

ře psali hlavně kvůli sobě, aby i dnes pořád věděli, co tehdy dávno napsali a proč právě takhle.

První řádky programu by měly obsahovat více informací než název --Prioritni inhibitor; tohle ví-

me už ze jména souboru! Hodilo by se přidat hlavně stručný popis, k čemu program vlastně slouží

a případně i jméno jeho autora.

Vhodná bývá i specifikace licence, pod níž je kód distribuován, aby ostatní věděli, jak ho mohou bez

obav používat. U akademických programů se často volí "GNU General Public License".

Jazyk – čeština může zůstat základem pro naše lokální programy v kurzu SPS. Chceme-li ale VHDL

kód zpřístupnit více lidem, pak bývá lepší zvolit si angličtinu, a to nejen pro komentáře, ale také od ní

odvozovat všechna jména proměnných.

VCCSW[0] INPUT LEDR[0]OUTPUT

N 1 Signed Integer

Parameter Value Type

A[n-1..0] Q[n-1..0]

prioritni_inhibitor

inst

Page 27: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

27

2. VHDL stylem "Structural" VHDL umožňuje popsat návrhy i hierarchickou strukturou — můžeme obvod rozdělit na dílčí jed-

nodušší entity, které samostatně odladíme, a poté popíšeme jejich propojení, podobně jako v editoru

schémat. Musíme zde poznamenat, že pro menší celky nenabízí VHDL vždy takovou přehlednost jako

grafická schéma. Jelikož opět použijeme jednoduché příklady, a tak výhody strukturálního popisu zde

příliš nevyniknou. Nicméně hodí se ho znát; často ušetří hodně práce. Textový program přece jen:

dovoluje lehčí porovnávání jednotlivých verzí než grafická schémata;

s počtem prvků (entit) roste i množství potřebných propojek. Od určité složitosti se grafická

schémata stávají nepřehledná a nepřinášejí už výhody, spíš naopak;

VHDL program lze lépe procházet ladicími nástroji, jak ukazuje příloha o simulacích.

2-1 Použití prioritního inhibitoru ve VHDL V předchozí kapitole "1-5 Tříbitový prioritní inhibitor — cyklus for-generate" jsme si vytvořili

program prioritní inhibitor. Umíme ho vložit do schématu a otestovat s deskou DE2. Lze ho však použít

i samostatně, přímo z VHDL, což demonstrujeme na jednoduchém programu, který plně nahrazuje sché-

ma "Obrázek 14" na straně 25:

--Test prioritniho inhibitoru -- 1

library ieee; use ieee.std_logic_1164.all; -- 2

entity test_inhibitoru is -- 3

port ( SW : in std_logic_vector(17 downto 0); -- 4

LEDR : out std_logic_vector(17 downto 0) ); -- 5

end; -- 6

architecture structural of test_inhibitoru is -- 7

component prioritni_inhibitor is -- 8

generic( N: natural := 18); -- 9

port ( A : in std_logic_vector(N-1 downto 0); -- 10

Q : out std_logic_vector(N-1 downto 0) ); -- 11

end component; -- 12

begin -- 13

inst_prioinhib : prioritni_inhibitor -- 14

generic map (N => 18) -- 15

port map ( A => SW, -- 16

Q => LEDR ); -- 17

end; -- 18 Program 13 - Prioritní inhibitor ve strukturálním popisu

Řádky 1 až 7 obsahují běžný začátek VHDL programu — odkazují na knihovny (na řádku 2) a po-

té deklarují entitu nazvanou test_inhibitoru, a proto soubor uložíme pod názvem test_inhibitoru.vhd.

V entitě definujeme v bloku port vstupy a výstupy, použijeme odkazy na desku DE2 coby přímé analogie

vstupů a výstupů ze schématu "Obrázek 13" na straně 22. Na řádce 7 je pak začátek architektury, opět

pojmenované dataflow.

Řádky 8 až 12 se vyskytují na místě definic lokálních proměnných sekce architektury, kam jsme

dříve vkládali i definice signálů. Nyní jsme tam uvedli blok entity přesně okopírovaný z řádek 3 až 7

"Program 12 - Prioritní inhibitor s generic" na straně 25. U okopírovaného bloku entity jsme jedině hradili

původní entity klíčovým slovem component, které jsme vložili i za end ukončující bloku, zde ho nelze

vynechat. Alternativně jsme mohli i uvést delší určení "end component prioritni_inhibitor".

Vložení deklarace bloku component lze považovat za něco podobného vkládání prototypů známé

funkcí z jazyka C nebo deklarací bloku interface PASCALu.

Page 28: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

28

Pozn. Kód se nám přeloží, i kdybychom v bloku

component uvedli neúplné deklarace ("incomplete

type declarations") zavedené ve VHDL-93 pro

složitější konstrukce, tedy vynechali default hodno-

tu u N v generic nebo opominuli rozsahy vektorů

v port. Zmiňujeme se o tom, protože VHDL kódy

nalezené na webu to občas používají, ale doporu-

čuje se používat úplné deklarace — ty mají menší

problémy s kompatibilitou.

component prioritni_inhibitor is -- 8 generic( N: natural); -- 9 port ( A : in std_logic_vector; -- 10 Q : out std_logic_vector ); -- 11 end component; -- 12

Program 14 - Nedoporučené použití neúplných definic v bloku

"component"!

Elegantnější i pohodlnější možnost pro zkrácení kódu si ukážeme později na straně 30 v kapitole věnova-

né tvorbě knihoven pomocí deklarace knihovních balíčků ("packages").

2-1.a) Sekce port map a generic map

Řádky 14 až 17 vytvoří instanci inhibitoru, tu pojmenujeme inst_prioinhib , dlouhý název se zde

sice nepoužije, ale hodí se později v simulaci pomocí ModelSim. Mapování generic parametru N, které

mu přiřadí hodnotu, a dále zapojení vstupů A a výstupů Q z define port lze provést dvěma způsoby:

a) Jmenné asociace ("keyword notation") mají syntaxi:

POZOR - všimněte si, že

generic map( generic_name1 => value1, generic_name2 => value2,

Členy jsou od sebe oddělené čárkami, nikoliv

středníky — jde o seznam asociací.

...

generic_nameN => valueN ) Za závorkou není ; — mapa pokračuje.

port map ( port_name1 => signal_name1, port_name2 => signal_name2,

Zde jde opět o seznam s členy oddělenými od

sebe čárkami.

...

port_nameN => signal_nameN ); Až zde se za ) vyskytuje středník— konec mapy.

Jelikož jde o asociativní seznamy, můžeme jejich členy uvést v libovolném pořadí, ale pro přehled-

nost se doporučuje zachovávat ho.

Označení generic_nameX udává jméno parametru zcela shodné s jeho deklarací v sekci component

generic a hodnota valueX specifikuje jemu přiřazenou hodnotu ve vytvářené instanci. Použijeme-li

místo hodnoty výraz, pak jeho výsledek musí být známý v době překladu — jde o konstantu.

Stejně tak port_nameX udává název vstupu nebo výstupu, a to opět, shodný s deklarací v component

port a signal_name1 určuje, k jakému signálu bude připojen. Pokud se jedná o vstup, lze jeho hodno-

tu specifikovat výrazem, který nemusí mít konstantní hodnotu v době překladu, na rozdíl od generic-

kých parametrů. Výstup musí být samozřejmě vždy mapován na signál. Pozn. Použití výrazů v mapo-

vání port map dovolí Quartus, žel překladač v ModelSimu je zpravidla odmítne z implementačních

důvodů, kvůli tomu bývá lepší výrazy napřed přiřadit do signálů a teprve ty mapovat na vstupy.

b) Poziční asociace ("positional notation") mají syntax:

generic map( value1, value2, ...

valueN )

port map ( signal_name1, signal_name2, ...

signal_nameN );

Hodnoty se v pozičních asociacích musí pochopitelně objevit přesně v pořadí deklarací jednotlivých

parametrů, vstupů a výstupům v bloku component. Pro případné použití výrazů zde platí pravidla uve-

dená v odrážce "a) Jmenné asociace".

Rozhodnutí zda použit jmenných či poziční asociace závisí plně na programátorovi. Pro jednodušší

komponenty lze volit méně upovídané poziční asociace, zejména v případech, kdy deklarace použitých

Page 29: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

29

component jsou vložené do entity, a tak si z nich lze snadno přečíst, čemu hodnoty vlastně přiřazujeme.

U složitějších komponent a u komponent definovaných v externích knihovnách se vyplatí napsat mnohem

přehlednější jmenné asociace, které navíc nabízejí vyšší imunitu vůči změnám v originálních entitách.

2-1.c) Sekce map a schéma

Program 13 na str. 27 odpovídá schématu "Obrázek 13" na straně 22. Můžeme ho přeložit jako

"top-level entity" a nahrát do desky DE2. Opačně lze i ze schématu vygenerovat VHDL soubor. Uložíme

schéma "Obrázek 13" jako "test_inhibitoru2.bdf", otevřeme ho a z hlavního menu Quartusu volíme "File->

Create/Update -> Create HDL Design File from Current File" a poté v dialogu zadáme VHDL.

Obrázek 15 - Příkaz "Create HDL Design File"

Ve složce projektu se nám vygeneroval soubor "test_inhibitoru2.vhd", který se však automaticky ne-

přidal do projektu. Jeho entita má název test_inhibitoru2, tedy stejný jako entita vytvořená ze schématu

"test_inhibitoru2.bdf". V projektu lze mít buď "test_inhibitoru2.vhd" nebo "test_inhibitoru2.bdf", nikoliv oba

soubory, aby nám překladač nehlásil chybu duplicity. Odstraníme tedy "test_inhibitoru2.bdf" (okno Project

Navigator záložka Files -> Remove File from Project") a můžeme vložit "test_inhibitoru2.vhd" (např. hlav-

ní menu Quartus:Project->Add Remove Files in Project…, najdeme soubor […], dáme [Add] a [OK]):

-- Copyright (C) 1991-2013 Altera Corporation… -- 1 LIBRARY ieee; USE ieee.std_logic_1164.all; LIBRARY work; -- 2 ENTITY test_inhibitoru2 IS -- 3 PORT( SW : IN STD_LOGIC_VECTOR(17 DOWNTO 0); -- 4 LEDR : OUT STD_LOGIC_VECTOR(17 DOWNTO 0) ); -- 5 END test_inhibitoru2; -- 6 ARCHITECTURE bdf_type OF test_inhibitoru2 IS -- 7 COMPONENT prioritni_inhibitor -- 8 GENERIC (N : INTEGER); -- 9 PORT( A : IN STD_LOGIC_VECTOR(17 DOWNTO 0); -- 10 Q : OUT STD_LOGIC_VECTOR(17 DOWNTO 0) ); -- 11 END COMPONENT; -- 12 BEGIN -- 13 b2v_inst : prioritni_inhibitor -- 14 GENERIC MAP(N => 18) -- 15 PORT MAP( A => SW, -- 16 Q => LEDR); -- 17 END bdf_type; -- 18 Program 15 - Automaticky generovaný VHDL kód

Vygeneroval se nám stejný kód; zde ho jen uvádíme zhuštěněji formátovaný a se zkrácenými úvod-

ními komentáři. Na řádce 2 má jen jeden nový prvek oproti našemu ručně udělanému programu — odkaz

na "LIBRARY work;", tj. případné knihovny v balíčcích ("packages") definované ve složce projek-

tu; ty zatím nemáme; povíme si o nich dále. Tvorba strukturálního VHDL popisu ze schémat může u slo-

žitějších obvodů ztrácet přehlednost díky pomocným proměnných, které si překladač někdy vytváří. Hodí

se však pro začátky — pomůže nám pro začátek jako šablona pro názornější manuální sestavení.

Page 30: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

30

2-1.c) Mapování vstupů a výstupů pro desku DE2

Pro Program 13 na straně 27 můžeme vygenerovat symbol, stejně jako pro každou jinou entitu,

a vložit ho do schématu, tedy mít další vrstvu. Vůbec nevadí skutečnost, že jsme vstupy a výstupy

u entity "test_inhibitoru" pojmenovali shodně s přiřazením na vývojové desce DE2 ("Assignments"). Na-

opak, volbou "Generate Pins for Symbol Ports", již dříve popsanou, rychle přiřadíme správně popsané vstu-

py a výstupy, a to prakticky bez práce.

Obrázek 16 - Test inhibitoru 2 vložený do schématu

Pozn. Zde raději připomeneme, že mapování vstupů a výstupů na FPGA "assignments" (desky DE2) se

provádí jedině pro vstupy a výstupy uvedené na úrovni "top-level entity", tedy jen pro zvýrazněné prvky

v obr. nahoře

. U všech vložených entit se názvy berou jen jako jejich lokální proměnné.

2-2 Rozšíření prioritního inhibitoru o enable Zadání: Přidejte k prioritnímu inhibitoru vstup en (enable), který se při en=´0´ uvede maximálně rychle

do ´0´ na všechny výstupy, zatímco při stavu en=´1´, bude inhibitor normálně pracovat.

Řešení: Úloha by šla vyřešit použitím inhibitoru s N+1 vstupy a na jeho nejvyšší vstup s indexem A[N]

připojit negovaný en, takže při en=´0´ by A[N]=´1´ a výstupy Q[N-1] až Q[0] by přešly do ´0´.

Nicméně náš programátorský úmysl bude jasnější, pokud použijeme prioritní inhibitor s N vstupy a za něj

připojíme multiplexor. Jako předlohu ("template") použijeme "Program 13 - Prioritní inhibitor ve struktu-

rálním popisu", který upravíme přejmenováním a doplněním deklarace en.

--Prioritni inhibitor s enable vstupem -- 1 library ieee; use ieee.std_logic_1164.all; -- 2 entity priroritni_inhibitor_enable is -- 3 generic( N: natural := 18); -- 4 port ( A : in std_logic_vector(N-1 downto 0); -- 5 en : in std_logic; -- 6 Q : out std_logic_vector(N-1 downto 0) ); -- 7 end; -- 8 architecture structural of priroritni_inhibitor_enable is -- 9

component prioritni_inhibitor is -- 10 generic( N: natural := 18); -- 11 port ( A : in std_logic_vector(N-1 downto 0); -- 12 Q : out std_logic_vector(N-1 downto 0) ); -- 13 end component; -- 14 signal Qtmp : std_logic_vector(Q´range); -- 15

begin -- 16

inst_prioinhib : prioritni_inhibitor -- 17

generic map (N => N) -- 18 port map ( A => A, Q => Qtmp ); -- 19

Q <= Qtmp when en='1' else (others=>'0'); -- 20 end; -- 21

Program 16 - Prioritní inhibitor s enable vstupem

Novou entitu jsme pojmenovali "priroritni_inhibitor_enable " a uložili do "priroritni_inhibitor_enable.vhd". Na

řádku 6 jsme přidali definici nového vstupu en. Pro vstup zvnějšku jsme použili A (řádek 5), pro výstu-

py opět Q (řádek 7) a pro generický parametr N (řádek 4). Záměrně jsme napsali názvy shodné s kom-

ponentou prioritni_inhibitor, abychom mohli demonstrovat skutečnost, zvýrazněnou i barvami pozadí, že

VCC SW[17..0] INPUT LEDR[17..0] OUTPUT SW[17..0] LEDR[17..0]

test_inhibitoru

inst2

Page 31: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

31

proměnné z hlavičky vložené komponenty (řádek 10 až 14) jsou dostupné jedině u mapování její instan-

ce (řádek 17 až 19), a to na levé straně členů => asociativního listu, jinde se na ně nedá odkázat.

Pokud uvedeme v generic map nebo port map asociaci XX=>YY, pak její levý člen XX se au-

tomaticky hledá mezi jmény komponenty, kterou právě mapujeme, tj. mezi jejími generickými parametry,

či mezi vstupy a výstupy. Pravý člen asociace YY se bude hledat mezi proměnnými definovanými v na-

šem obvodu v entitě a v architektuře. Napíšeme-li asociaci N=>N, pak levé N bude vztaženo k N v sekci

generic map na řádku 18 a pravé N se vezme z generic na řádku 4.

Řádek 20 obsahuje příkaz pro vytvoření multiplexoru. Příkaz when…else obecně vede na kaskádu

multiplexorů při více podmínkách, tj. máme-li více řádků s when…else. Pro jednu jednoduchou podmínku

(en='1') je úplně jedno, zda použijeme příkaz Q <= Qtmp when en='1' else (others=>'0'); nebo delší kon-

strukci: with en select Q<= Qtmp when '1', (others=>'0') when others; — výsledkem bude

vždy jeden multiplexor. Upřednostnili jsme pochopitelně kratší zápis when…else.

2-2.a) Inicializace proměnných vektorů asociací others=>

Klíčové slovo others znamená veškeré nepoužité hodnoty. Kromě příkazů, viz nahoře, ho lze užít

i pro vytváření asociačních listů inicializujících proměnné, ovšem jedině za předpokladu, že bude přesně

známa délka výsledku už v době překladu, tj. z našeho kódu půjde jednoznačně odvodit velikost proměn-

né, do níž zapisujeme. Na levé straně asociace inicializací stojí určení indexů v poli s možnými směry

směry jak to tak downto a na pravé straně pak požadovaná hodnota jeho členu či členů.

Možnosti nejlépe přiblíží následující demo-příklad:

library ieee;use ieee.std_logic_1164.all; entity asociace is

generic(N:natural:=8); port ( X1, X2, X3, X4, X5, X6, X7 : out std_logic_vector(N-1 downto 0) ); end entity; architecture structural of asociace is

begin -- Pro N = 8 Pro N = 12

X1 <= (others=>'0'); -- X1="00000000" X1="000000000000"

X2 <= (others=>'1'); -- X2="11111111" X2="111111111111"

X3 <= (others=>'Z'); -- X3="ZZZZZZZZ" X3="ZZZZZZZZZZZZ"

X4 <= (0=>'0', others=>'1'); -- X4="11111110" X4="111111111110"

X5 <= (N-1=>'0', others=>'1'); -- X5="01111111" X5="011111111111"

X6 <= (N-1=>'0', 1=>'0', others=>'1'); -- X6="01111101" X6="011111111101"

X7 <= (N-1 downto N-3=>'1', 1 to 3=>'1', others=>'0'); -- X7="11101110" X7="111000001110"

end; Program 17 - Demonstrace použití others pro inicializaci

Všimněte si, že hodnota u inicializační asociace se specifikuje shodně s datovým typem prvků pole,

i když výsledek ovlivní více členů; jde o asociace na indexované prvky pole. Pole std_logic_vector má čle-

ny výčtového datového typu std_logic, a tak píšeme pravé strany asociací v ´ ´ apostrofech.

Při inicializace X7 jsme v rozsazích použili jak směr downto tak i to , což zde můžeme, protože defi-

nujeme asociaci pro vytvoření inicializační konstanty, až její výsledek se přiřadí vektoru.

Kdybychom chtěli X7 dát stejnou hodnotu bez asociativního listu, měli bychom více <= příkazů:

X7(N-1 downto N-3) <= "111"; X7(N-4 downto 4) <=(others=>'0'); X7(3 downto 1) <="111"; X7(0)<='0';

Aplikaci others jsme se v nich stejně nevyhnuli — prostřední část vektoru X7(N-4 downto 4) má pro-

měnlivou délku a bez others to tady nejde. V příkazech jsme již museli dodržovat směr downto určený

v definicí vektoru. Pokus o použití směru to (např. X7(1 to 3) <="111"; ) by samozřejmě vyvolal chybové

hlášení obsahující text: "…range direction of object slice must be same as range direction of object".

Page 32: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

32

2-3 Vytvoření vlastní knihovny ("package") V kapitole "1-3.d) Dekodér pro lineární ukazatel s výstupy na jednotlivé " na straně 19 jsme slíbili,

že modifikaci dekodéru vytvoříme elegantněji, bez opakování kódu. Samozřejmě můžeme postupovat

stejným stylem jako v předchozí kapitole "2-2 Rozšíření prioritního inhibitoru o enable", tj. vložit hla-

vičku component a poté provést její mapování.

Nicméně neustálé vkládání deklarací komponent před každým jejich použitím je, jak se to lidově ří-

ká, "votravné". Vždyť pro podobné situace existuje v jazyce C direktiva preprocesoru "#include" a v C#

se zase používá příkaz using. V Java máme možnost odkázat na vytvořený "package". Stejný koncept se

používá i ve VHDL. Vytvoříme package obsahující potřebné deklarace, na který jen odkazujeme:

-- Knihovna kodu vytvorenych v uvodu do VHDL -- 1 library ieee; use ieee.std_logic_1164.all; -- 2 -- 3

package uvod_knihovna is -- 4 -- 5

component majorita is -- 6 port ( a, b, c : in std_logic; -- 7 y, y1 : out std_logic ); -- 8 end component; -- 9 -- 10 component dekoder2linearni is -- 11 port ( A : in std_logic_vector(1 downto 0); -- 12 Q : out std_logic_vector(2 downto 0) ); -- 13 end component; -- 14 -- 15 component prioritni_dekoder is -- 16 port ( INT : in std_logic_vector(3 downto 1); -- 17 Q : out std_logic_vector(1 downto 0) ); -- 18 end component; -- 19 -- 20 component prioritni_inhibitor is -- 21 generic( N: natural := 18); -- 22 port ( A : in std_logic_vector(N-1 downto 0); -- 23 Q : out std_logic_vector(N-1 downto 0) ); -- 24 end component; -- 25 -- 26 component priroritni_inhibitor_enable is -- 27 generic(N: natural := 18); -- 28 port ( A : in std_logic_vector(N-1 downto 0); -- 29 en : std_logic; -- 30 Q : out std_logic_vector(N-1 downto 0) ); -- 31 end component; -- 32 -- 33

end; -- 34 Program 18 - Knihovna kódů vytvořených v úvodu do VHDL

Na řádku 2 odkazujeme na standardní knihovny, neboť v nich se nacházejí definice datových typů

std_logic a std_logic_vector, které používáme v deklaracích komponent.

Na řádku 4 definujeme náš název knihovny "uvod_knihovna" za klíčovým slovem package. Poté

následují deklarace komponent. Vložili jsme sem všechny dosud vytvořené. Jejich definice zůstávají ve

stejnojmenných souborech, takže je překladač snadno najde.

Na řádku 34 končí deklarace knihovna klíčovým slovem end, ve VHDL-93 a vyšším lze za něj

přidat i klíčové slovo package a případně i název knihovny uvod_knihovna, podobně jako u entity, viz

"Tabulka 1 - možnosti zakončení deklarace entity" na str. 8.

Náš balíček obsahuje pouze hlavičky komponent. Alternativně lze do něho přidat:

Page 33: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

33

definice datových typů a subtypů pro použití v našich programech. Baliček představuje ostatně jedi-

nou možnost jak naše vlastní typy a subtypy používat už v bloku entity;

definice konstant;

pro VHDL psané stylem "behavioral", který úvod nezahrnuje, a pro testovací části kódu nazývané

"testbench" může knihovna obsahovat i deklarace funkcí, procedur a jiných prvků, ale pak v ní musí

existovat i další blok package body … end , kde jsou tyto prvky definované. Zájemce o podobné

speciality převyšující rámec kurzu možno odkázat na webové stránky, hledání "vhdl package".

2-3.a) Dekodér pro lineární ukazatel s výstupy na jednotlivé bity pomocí knihovny

Nyní můžeme lehce vytvořit modifikaci dekodéru pro lineární ukazatel s výstupy na jednotlivé bity

ze strany 19, neboť už nemusíme vkládat deklaraci použité komponenty — ta je obsažena v naší knihov-

ně.

--Dekoder pro linearni ukazatel s nevektorovymi I/O -- 1 library ieee; use ieee.std_logic_1164.all; -- 2 library work; use work.uvod_knihovna.all; -- 3 -- 4

entity dekoder2linearniC is -- 5 port ( A1, A0 : in std_logic; -- 6 Q2, Q1, Q0 : out std_logic ); -- 7 end; -- 8 -- 9

architecture structural of dekoder2linearniC is -- 10 signal Q : std_logic_vector(2 downto 0); -- 11 begin -- 12 inst_dek2lin : dekoder2linearni -- 13 port map (A=> A1 & A0, Q=>Q); -- 14 Q2<=Q(2); Q1<=Q(1); Q0 <= Q(0); -- 15 end; -- 16

Program 19 - Dekodér pro lineární ukazatel s výstupy na jednotlivé bity pomocí knihovny

Na řádku 3 vkládáme odkaz na knihovnu; která se nachází v projektu; na ten odkazuje určení work.

Syntaxe zápisu je podobná jako u standardní knihovny na řádku 2.

Řádek 5 až 8 deklaruje vstupy a výstupy entity dekoder2linearniC.

Řádek 13 a 14 vytvoří instanci dekodéru dekoder2linearni nazvanou inst_dek2lin. Pro ma-

pování vstupů můžeme v Quartus použít výraz "A1 & A0" sjednocení bitových signálů do vektoru,

zatímco výstupy je nutné opět rozepsat po jednotlivých bitech přes pomocnou proměnnou.

Kód je nyní dokonce kratší než původní Program 5 na straně 19 a navíc i zachovává zásadu sdílení kódu.

2-4 Zapojení prioritního dekodéru a lineárním ukazatelem Zadání: Vytvořte ve VHDL obvod skládající se z prioritního dekodéru přerušení a indikátoru výstupního

čísla pomocí dekodéru pro lineární displej, dle schématu:

Obrázek 17 - Prioritní dekodér s lineárním ukazatelem

V zapojení si všimněte pojmenovaného vodiče, zvýrazněného červeně — pojmenování lze provést v edi-

toru přes kontextové menu vodiče volbou "Properties". Hodilo by se nám, kdybychom generovali VHDL

VCCKEY[3..1] INPUT

LEDG[2..0]OUTPUT

INT[3..1] Q[1..0]

prioritni_dekoder

inst

A[1..0] Q[2..0]

dekorer2linearni

inst1

NOT

inst2

Qtmp[1..0]

Page 34: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

34

kód ze schématu, což si můžete zkusit za domácí úkol, pokud chcete — překladač pak vytvoří pomocný

signál stejného jména. Nicméně kód není složitý, lze ho lehce napsat přímo ve VHDL:

--Prioritni dekoder s linearnim ukazatelem -- 1

library ieee; use ieee.std_logic_1164.all; -- 2

library work; use work.uvod_knihovna.all; -- 3

entity prioritni2linearni is -- 4

port ( KEY : in std_logic_vector(3 downto 1); -- 5

LEDG : out std_logic_vector(2 downto 0) ); -- 6

end; -- 7

architecture stuctural of prioritni2linearni is -- 8

signal Qtmp : std_logic_vector(1 downto 0); -- 9

signal nkey : std_logic_vector(3 downto 1); -- 10

begin -- 11

nkey<= not KEY; -- 12

inst_priodek : prioritni_dekoder -- 13

port map (INT=> nkey, Q=>Qtmp); -- 14

inst_dek2lin : dekoder2linearni -- 15

port map (A=>Qtmp, Q=>LEDG); -- 16

end; -- 17 Program 20 - Prioritní dekodér s výstupem na lineární ukazatel

Řádky 2 a 3 deklarují knihovny a můžeme je beze změny okopírovat z předchozího kódu v Program

19 na straně 33.

Řádek 4 až 7 obsahuje entitu, v níž zadáme název našeho obvodu " prioritni2linearni " a poté běžným

způsobem definujeme vstupy a výstupy, které připojíme na desku DE2.

Řádek 8 a 9 zahajuje architekturu. V její hlavičce definujeme pomocný signál Qtmp pro propojení

obou obvodů a signál nkey.

Řádek 12 do signálu nkey připojíme negaci vstupů KEY; nestisknuté KEY dávají totiž ´1´. Signál použi-

jeme pro mapování port map bez použití výrazu — v příloze plánujeme totiž otestovat kód v prostředí

ModelSim, kde překladač nebere nekonstantní výrazy u mapování instancí.

Řádek 13 a 14 obsahuje vytvoření instance prioritního dekodéru. Na jeho vstup INT mapujeme negaci

signál nkey. Výstupy Q vyvedeme na pomocný vodič Qtmp — bez něho nelze propojení provést. Na

vstupy, výstupy a parametry instancí odvolávat jen uvnitř jejich mapování (příkazy port map a gener-

ic map). Pozn. Ve VHDL nelze odkazovat na prvky instancí zápisy v objektovém stylu, tedy např. psát

něco jako " inst.Q" apod.

Řádek 15 a 16 mapuje druhou instanci — dekodér na lineární displej. Na jeho vstup A připojíme vo-

dič Qtmp a na výstupy Q zelené led-diody LEDG.

Pozn. Pro obě instance jsme použili delší názvy, což nám umožní lepší orientaci při simulaci obvodu

Obvod je hotový, můžeme ho přeložit a vyzkoušet. Zde lze postupovat dvěma způsoby. Buď

1) přeložíme " prioritni2linearni.vhd", vytvoříme pro něj *.vwf soubor a provedeme simulaci v pro-

středí Quartus, viz stránky SPS kurzu.

2) nebo si napíšeme testbench a zkusíme obvod simulovat, což je preferovaný způsob používaný

v profesionální praxi; teprve při něm vyniknou výhody VHDL oproti schématu. Popis postupu 2)

je poněkud rozsáhlý a kvůli tomu byl zařazený do přílohy.

Page 35: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

35

Závěr Příkladný úvod do VHDL není úplný. Nevznikl jako kompletní učebnice, ale jako rychlé seznámení

se základy VHDL v prostředí Quartus. Chybí zde například části o reprezentaci čísel a dále především

styl "behavioral", v němž se obvod popisuje svojí funkčností, která se od něho žádá. Po zkušenostech

s předchozí výukou můžeme konstatovat, že studentům obvykle nedělá větší potíže tvořit v "behavioral"

stylu, protože VHDL kód se v něm podobá klasickému programu. Problémy jim činí jedině provést

vhodný popis řešení, ze kterého lze obvod dobře syntetizovat. Někteří "experti" z minulých let vyčerpali

téměř celou kapacitu FPGA obvodu i jednoduchými stopkami se sedmisegmentovým displejem. Nepro-

brané části vyžadují delší vysvětlení, a tak si je necháme na přednášky.

Úvod může obsahovat nejasnosti ve výkladu, případně překlepy, nepřesnosti či jiné prohřešky, které

unikly korekturám. Autor uvítá, pokud mu o nich napíšete, nebo pošlete své připomínky a náměty na roz-

šíření stávajících částí pro příští školní rok.

~ o ~

Page 36: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

36

Příloha A: Testbench pro ModelSim Ukážeme si, jak lze vytvořit simulaci pro ModelSim. Jde o profesionální techniku, kterou doporu-

čujeme ve VHDL používat. Není rozhodně podmínkou pro absolvování kurzu SPS. Jakmile však zvlád-

nete jednu simulaci, další vytvoříte již rychleji — postupy jsou podobné. Naučíte-li se aspoň krapánek

"simulovat", můžete získat špetku výhod, minimálně ždibec úspory svého času pro trošku jiné aktivity.

A-1 Vytvoření programu typu Testbench Pokud chceme nějaký program zkoušet, musíme pro něj napřed napsat testbench, jakýsi generátor

příslušných testovacích signálů. Při simulacích v Quartus se automaticky vytvářel ze souboru *.vwf, do

kterého se v jeho editoru "Simulation Vaweform Editor" nakreslily požadované průběhy vstupů. Z nich se

pak vygeneroval testbench.

Pro vyzkoušení našeho "Program 20 - Prioritní dekodér s výstupem na lineární ukazatel" ze strany

34, by vstupní soubor "prioritni2linearni.vwf" mohl vypadat třeba takto:

Kreslíme se změnami po 20 ns postupně všechny možné vstupní kombinace pro klávesy KEY (tlačítko

KEY dává ´0´ při stisknutí, a proto máme průběhy negované). Poté můžeme spustit Quartus II Simulator

.Napřed nastavíme "Simulation->Options - Quartus II Simulator" a poté spustíme funkční simulaci, která testu-

je jen rovnice, a to příkazem "Simulation->Run Functional Simulation":

Funkční simulaci jsme sice provedli relativně rychle, ale tady končí naše časová úspora. Nyní začí-

náme pomalu luštit průběhy, zdalipak se náš obvod chová mravně a netropí nějaké neplechy. Louskání

průběhů simulací si případně zopakujeme po každé změně v kódu. Po čase si položíme otázku, jestli by

testování nešlo zautomatizovat. Podobnou možnost nabízí právě VHDL testbench.

Pozn. U úloh zadávaných v kurzu SPS vystačíte s funkčními simulacemi doplněnými zprávami

z Quartus překladače v položce" TimeQuest Timing Analyzer". Nebudete řešit tak náročné obvody, abyste

museli zkoumat časové simulace uvažující i charakteristiky interních prvků FPGA. Ty sice ukáže

i Quartus simulátor "Simulation->Run Timing Simulation", ale jen v méně přesné formě.

Page 37: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

37

VHDL testbench uvedeme v podobě vhodné pro kombinační obvody a poté ho postupně vysvětlí-

me. Kód není těžký a lze ho velmi lehce modifikovat pro další obvody:

--Testbench - Prioritni dekoder s linearnim ukazatelem -- 1 library ieee; use ieee.std_logic_1164.all; -- 2 entity tb_prioritni2linearni is -- 3 end; -- 4 architecture testbench of tb_prioritni2linearni is -- 5 component prioritni2linearni is -- 6 port ( KEY : in std_logic_vector(3 downto 1); -- 7 LEDG : out std_logic_vector(2 downto 0) ); -- 8 end component; -- 9 -- 10 type stimuls is array (0 to 7) of std_logic_vector(2 downto 0); -- 11 constant sKEY : stimuls := ("000","001","010","011","100","101","110","111"); -- 12 constant sLEDG : stimuls := ("000","001","011","011","111","111","111","111"); -- 13 signal tbKEY : std_logic_vector(3 downto 1); -- 14 signal tbLEDG : std_logic_vector(2 downto 0); -- 15 -- 16

begin -- 17 inst_prio2lin : prioritni2linearni -- instance testovaného programu -- 18 port map (KEY=> tbKEY,LEDG=>tbLEDG); -- 19 generator : process -- 20 begin -- 21 for i in stimuls'range loop -- 22 tbKEY <=not sKEY (i); -- KEY davaji negovanou hodnotu -- 23 wait for 20 ns; -- cekej 20 ns -- 24 assert tbLEDG = sLEDG (i) -- 25 report "vystupy odlisne pri indexu " & integer'image(i); -- 26 end loop; -- 27 wait; -- nekonecne cekani, simulace se zde zastavi -- 28 end process; -- 29 end architecture testbench; -- 30

Program 21 - VHDL testbech pro dekoder dekodér s výstupem na lineární ukazatel

Řádek 2 obsahuje standardní knihovny.

Řádek 3 a 4 definuje entitu - pro programy typu testbech má vždy tento tvar, tj. uvádí se pouze její

název tb_prioritni2linearni a chybí deklarace port nebo generic.

Řádek 5 zahajuje architekturu. Nazvali jsme ji testbench.

Řádek 6 až 9 vkládá deklaraci component zkoušené entity prioritni2linearni. Snadno ji vytvoříme

známým postupem, a to okopírováním bloku entity ze souboru prioritni2linearni.vhd.

Řádek 11 — vektory vstupů i výstupů prioritni2linearni mají stejné délky 3 členy, a tak si pro ně vy-

tvoříme datový typ stimuls popisující pole osmi prvků typu std_logic_vector(2 downto 0);

Řádek 12 obsahuje konstantní pole definující požadované simulační vstupy sKEY . Ty jsou přímou

analogií vstupních signálů zadaných ve "Vaweform" editoru na předchozí stránce, akorát jsme je pro

přehlednost zde nenapsali negované — tohle uděláme raději programově.

Řádek 13 obsahuje definice požadovaných simulačních výstupů sLEDG, které budeme v programu

automaticky kontrolovat.

Řádek 14 a 15 obsahuje definice proměnných shodných se vstupy a výstupy testované komponenty,

pro přehlednost jsme před jejich názvy napsali prefix tb od testbench.

Řádek 18 a 19 obsahuje příkaz vytvoření instance zkoušeného obvodu prioritni2linearni, instanci

pojmenujeme inst_prio2lin, a její vstupy a výstupy se připojíme na naše testovací signály.

Řádek 20 deklaruje blok procesu. Příkaz patří do zde neprobraného stylu "behavioral" programování.

Uvnitř procesů se používají příkazy zařazené do skupiny "Sequential Statements" — ty se neprovádějí

Page 38: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

38

paralelně, ale vykonávají se sekvenčně jeden po druhém tak jako v běžných programech. Musíme

však zdůraznit, že způsob, jakým je zde napsaný proces, se povoluje jedině v simulacích, ale v těch

má zase většinou tento tvar. Pro syntézu obvodů se proces musí psát jiným způsobem, o němž si bu-

deme povídat na přednáškách - tenhle proces by v reálném obvodu nefungoval.

Strukturu procesu a jeho součinnost s testovaným obvodem ilustruje následující obrázek. Z něho vi-

díme, že z procesu vznikl obvod generátoru připojený k testované entitě.:

Řádek 22 zahajuje programový sekvenční cyklus for - loop , který do proměnné cyklu i typu integer

přiřazuje postupně hodnoty 0 až 7, tj. všechny indexy pole simulačních vstupů.

Řádek 23 načte testovací vstup z indexu i a jeho negovanou hodnotu pošle po signálu tbKEY příka-

zem "tbKEY <=not sKEY (i); " vedoucím na vstup KEY ( port map na řádku 19).

Řádek 24 obsahuje pokyn pro simulátor, aby se další příkaz bloku procesu vykonal až za 20 nano-

sekund. Zdržení jsme vložili kvůli tomu, aby nové hodnoty na vstupech KEY měly čas k ovlivnění vý-

stupů LEDR. Pauza se týká jen procesu, simulátor bude dál pilně počít reakce inst_prio2lin na vstupy.

Řádek 25 až 26 testuje, samozřejmě až po uplynutí předchozího čekání 20 ns, zda výstupy obvodu se

shodují s požadovanými. Při neshodě se vypíše chybové hlášení obsahující zadaný text a hodnotu in-

dexu převedenou na řetězec pomocí atributu integer'image(i); Pozn. Hodnoty vstupů a výstupů nevy-

pisujeme záměrně. Konverze typu std_logic_vector na řetězec je sice možná, ale potřebné funkce

nejsou zahrnuté ve standardních knihovnách a musely by se vkládat celé jejich definice. Pro zjedno-

dušení kódu jsme je raději vynechali. Zájemci naleznou vše potřebné na webu.

Řádek 27 končí cyklus a musí mít tvar "end loop;" — zde za end zde nelze vynechat loop.

Řádek 28 obsahuje příkaz wait, avšak bez zadaného času. Simulátor bude čekat nekonečně dlouho, tj.

zastaví se simulace.

Řádek 29 ukončuje blok procesu a opět zde nelze za end vynechat klíčové slovo process.

Řádek 30 končí architekturu. Máme již trochu delší kód, a tak jsme místo jednoduchého koncového

end zvolili i přidání klíčového slova architecture a názvu architektury testbench.

Budeme-li chtít náš testbench použít pro zkoušení jiného obvodu, vyměníme jen prioritni2linearni kom-

ponentu za novou a upravíme kód pro její instanci. Jakmile definujeme požadované testovací vektory,

můžeme zkoušet. Testbench stačí jen spustit a ihned víme, zda pracuje dle našich požadavků.

Pozn. V Quartusu II není tb_prioritni2linearni.vhd přeložitelný kvůli použití wait for <time>. Můžeme

program maximálně otestovat z lišty nástrojů VHDL editoru tlačítkem "Analyze Current File". Úplný

překlad by skončil chybou "Error (10533): VHDL Wait Statement error at tb_prioritni2linearni.vhd(25):

Wait Statement must contain condition clause with UNTIL keyword". Nicméně příkazy wait se v syntéze

už nepoužívají, a to ani wait until zmíněné v chybové hlášce — to zůstalo kvůli ve VHDL kvůli simulacím

a pro zpětnou kompatibilitu se staršími verzemi VHDL. Pro syntézu existují lepší konstrukce.

KEY[3..1] LEDG[2..0]

priority2linearni

inst_prio2lin

generator : process

tbKEY

tbLEDG

"000","001","010","011","100","101","110","111" sKEY(i)

sLEDG(i) shodné?

"000","001","011","011","111","111","111","111"

20 ns

"odlišné při indexu i"

různé

i 0 1 2 3 4 5 6 7

tb_prioritni2linearni

Page 39: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

39

A-2 Spuštění Testbench v ModelSim Altera Program ModelSim-Altera Starter Edition se nainstaluje přímo s vývojovým nástrojem Quartus při jeho

instalaci z ISO-image. Lze ho používat bezplatně, ale neumožní některé postupy potřebné pro profesio-

nální vývoj. V bezplatné verzi provádí jen funkční simulace, tj. bez uvažování skutečných časů v přelože-

ném FPGA. Dovoluje však vkládat do VHDL kódu "breakpointy", takže snáze zjistíme nepovedené části.

Zde předpokládáme, že máte instalovaný "ModelSim-Altera 10.1d (Quartus II 13.0sp1)", tedy verzi

shodnou s výukovými laboratořemi.

Ve vašem Quartus projektu existuje podadresář "<project_root_directory>\simulation\modelsim\" pro Model-

Sim — vytvořte ho, pokud tam dosud není, a máte-li ho, raději smažte vše v něm, aby se vytvářel no-

vý ModelSim projekt bez interakce s možnými soubory automaticky generovanými Quartusem.

Předpokládáme dále, že zkoušená entita v souboru "prioritni2linearni.vhd" se Vám po označení jako

top-level entity přeložila bez chyb úplným překladem v Quartusu.

Spusťte ModelSim. Pozn. Návody k ModelSim najdete v menu Help->PDF… Není ale potřeba číst je

dopředu, další text bude srozumitelný i bez nich, ale hodí se později pro případné rozšíření vědomostí.

Doporučujeme především Tutorial, a to jeho kapitoly 1 až 4 a 6, které obsahují základní věci, a kapi-

tolu 2 příručky "User´s Manual", kde se vysvětluje uživatelské rozhraní ModelSim.

Vytvoření projektu ModelSim

Z hlavního menu ModelSim volíme

File->New->Project…

V dialogu "Create Project"

vyplníme libovolné jméno projektu, např. "test";

v Project Location nastavíme cestu k simulačnímu

adresáři v projektu Quartusu, abychom měli vše

pohromadě — pro lepší zobrazení cest v obrázcích

jsme přesunuli Quartus projekt do "E:/Uvod/", takže

zadáme "E:/Uvod/simulation/modelsim".

Ostatní položky necháme ve výchozím stavu

a dialog potvrdíme [Ok].

Po zavření "Create Project" tlačítkem [OK], se objeví

nabídka "Add Items…", volíme "Add Existing File" pro

přidání souborů, které chceme simulovat.

Objeví se nám dialog "Add file to Project", v němž stis-

kem [Browse] otevřeme "Select files to add to project"

dialog pro prohlížení disku.

Z projektu vybereme všechny soubory,

které bude simulace potřebovat:

tb_prioritni2linearni.vhd

prioritni2linearni.vhd

prioritni_dekoder.vhd

dekoder2linearni.vhd

uvod_knihovna.vhd

a poté ukončíme výběr tlačítkem [Open].

Vybraná jména se objeví v dialogu "Add file to Project". Ponecháme "Reference from current location" volbu

vybranou, aby se na soubory jen odkazovalo. Poté dialog zavřeme [OK].

Page 40: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

40

Seznam souborů uvidíme v ModelSim okně na zá-

ložce "Project".

Pokud jsme zapomněli na nějaký soubor, můžeme

ho přidat, když pravou myší klikneme do okna

Project a volíme "Add to project"->"Existing File"

v jeho kontextovém menu.

Alternativní přidání souboru nabízí hlavní menu

"Project"->"Add to project"->"Existing File".

Máme-li nějaký soubor omylem navíc, odstraníme

z projektu pomocí klávesy [delete].

ModelSim vložil soubory a nastavil jejich pořadí, které nemusí být

správné. Volba "Compile"->"Compile Order…" z hlavního menu

otevře dialog, v němž lze pořadí upravit i ručně. Zde ale dáme

přednost automatické korekci volbou [Auto Generate], která vy-

volá i překlad. Po něm zavřeme dialog [OK].

Soubory se přeložily a jejich pořadí se změnilo na správné:

V dolním okně Transcript by se měly objevit spokojené

hlášky překladače potvrzující bezchybný průběh.

Pozn. ModelSim generuje výrazně méně hlášek než Quartus,

ale zato často píše dost podstatné věci, takže doporučuji

pečlivě sledovat okno Transcript. Je-li příliš plné, lze ho vy-

mazat přes jeho kontextové menu volbou Clear.

Opětovný překlad souborů lze kdykoliv později spustit z hlavního menu "Compile"->"Compile All".

Nyní přepneme na záložku [Library], kde v knihovně "work" máme přeložené soubory. U uvod_knihovna je

typ "package" a u ostatních "entity". Pozn. Souborům s testbench bývá někdy zvykem dávat příponu "*.vht", ten

náš by se mohl jmenovat "tb_prioritni2linearni.vht". Není to však povinné. Volili jsme "*.vhd" z ryze praktických

důvodů. Quartus překladač odmítá "*.vht" soubory jako nepřípustné typy a nedají se v něm ani otestovat.

Spustíme simulaci, avšak ne z hlavní-

ho menu "Simulate->Start Simulation";

které nabízí mnoho parametrů pro

speciální případy. Nám stačí výchozí

nastavení — pro něj lze simulaci spus-

tit jednodušeji.

Vybereme v [Library] "work" soubor

s naším testbench tb_prioritni2linearni.

Pravou myší vyvoláme jeho kontexto-

vé menu, v němž zvolíme simulaci

bez optimalizace, aby se nám neredu-

kovaly proměnné a příkazy a viděli

jsme vše.

Page 41: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

41

ModelSim změnil svůj vzhled - přepnul svůj Layout (uspořádání oken) z původního "NoDesign" na nový

"Simulate".

Pozn. ModelSim dovoluje uchovat uspořádání oken.

Zpočátku máme 4 výchozí a k nim lze přidat svoje

vlastní, když momentální uspořádání oken uložíme

z hlavního menu "Layout->Save layout As…". Mezi

uspořádáními pak můžeme volně přepínat.

Entita tb_prioritni2linearni obsahuje ve svém stromu do

ní vložené entity. Kvůli tomu jsme instance pojmeno-

vávali raději delšími názvy, aby nám při simulacích

usnadnily orientaci.

V stromu výpisu vidíme také odkazy na čísla řádek

kódu, na ty lze vložit breakpointy.

Nastavíme dále graf průběhů.

Pravou myší vyvoláme kontexto-

vé menu u tb_prioritni2linearni

a volíme "Add to->Wave->All items

in region and below". Ukáže se

nám okno typu Wave , do kterého

se nám vložily všechny proměn-

né z našich VHDL souborů.

Pozn. Okno Wave se nám může objevit buď zahlou-

bené do hlavního okna ModelSim nebo jako samo-

statné okno, které lze umístit kdekoliv na plochu.

Stav jeho zahloubení se mění volbou Dock/Undock

z kontextového menu jeho podokna— pravou myší

na ikonu pod hlavním menu Wave.

Nyní již lze spustit simulaci volbou z hlavního

menu "ModelSim Simulate->Run->Run -All".

Simulace poběží až po první breakpoint nebo až ke

skončení testbench, což bude náš případ, protože

na konci procesu generate máme vložené nekoneč-

né čekání příkazem wait.

Pozn. Velké černošedé plochy okna Wave v obrázku

dole byly graficky upravené pro tisk inverzemi barev.

Page 42: Příkladný úvod do VHDL - cvut.czdcenet.felk.cvut.cz/edu/fpga/doc/PrikladnyUvodDoVHDL.pdf · Verze 1.0 ze dne 13. září 2013 Příkladný úvod do VHDL Richard Šusta Katedra

42

Vybereme okno Wave obsahující záznam průběhů všech proměnných. Stiskneme klávesu F (Zoom Full),

abychom viděli celé průběhy. Alternativně můžeme na liště nástrojů Zoom kliknout na ikonu , která

plní stejnou funkci.

V okně Transcript se nám zatím nevypsala žádná chybo-

vá hláška — náš program neobsahuje chybu.

Úmyslně ji vložíme, abychom viděli, co se stane. Na zá-

ložce [sim] vybereme levým dvojklikem myši entity

tb_prioritni2linearni obsahující náš testbench. Zobrazí se

kód VHDL Program 21 ze str. 37. Vypneme jeho ochra-

nu proti náhodnému přepsání zrušením volby Read Only

v kontextovém menu (pravou myší na text v editoru).

Nyní změníme v hodnotách inicializaci pole řádku 13

constant sLEDG : stimuls := ("000","001","011","011","111","111","111","111"); Na indexu 3 přepíšeme původní "011" na chybné "111": ("000","001","011","111","111","111","111","111");

Soubor uložíme a zapneme jeho Read Only ochranu.

Přeložíme vše (Compile->Compile All) a spustíme simulaci od začátku (Simulate->Restart…). V Restart dialo-

gu, který se objeví, necháme všechny položky vybrané, aby se zachovaly stávající prvky, a potvrdíme to

volbu [OK]. Poté opět spustíme simulaci (Simulate->Run->Run -All).

Proběhne znovu celá od začátku až do konce. V okně Transcript se však objevila hláška příkazu report:

# ** Error: vystup nesouhlasi pri indexu 3

# Time: 80 ns Iteration: 0 Instance: /tb_prioritni2linearni

Necháme si tedy simulaci programu zastavit na chybě, abychom věděli, co se děje. Vložíme breakpoint

do tb_prioritni2linearni.vhd na řádek 26, tj. na příkaz report (dvojklikem levou myší na číslo řádku). Zadáme

zas "Simulate->Restart…" a novou simulaci "Simulate->Run->Run -All".

Simulace se zastaví na na-

šem breakpointu. Najedeme-

li myším kurzorem na pro-

měnnou, která nás zajímá,

uvidíme její hodnotu. Na

obrázku vlevo jsme zvolili

tbLEDG na řádku 19.

Obrázek 18 - Breakpoint při simulaci

Klávesou F10 lze pokračovat v simulaci. Máme-li více breakpointů, pak se

její běh zastaví na dalším z nich; více viz již zmíněné návody v menu Help.

Program lze také krokovat, k tomu slouží tlačítka na liště nástrojů:

~ . ~

NNaauuččíímmee--llii ssee vvyyuužžíívvaatt MMooddeellSSiimm,, uuššeettřříímmee ssii ččaass,, aa ttoo zzeejjmméénnaa ppřřii ppssaanníí VVHHDDLL ssttyylleemm ""bbeehhaavviioorraall"" bbllíízz--

kkéémmuu kkllaassiicckkýýmm pprrooggrraammůůmm.. BBeezz ppoořřááddnnééhhoo ssiimmuulloovváánníí llzzee pprrooggrraamm llaaddiitt lleeddaa mmeettooddoouu ppookkuuss--oommyyll::

ZnovuALépe: PoEditujeme(); Přeložíme(); NahrajemeDoDE2(); BedlivěZkoumáme();

if("Neběží? Hmmm, zas ne, a tak zas") goto ZnovuALépe;

KKaažžddýý nnáávvrrhh ssee mmuussíí nnaakkoonneecc oovvěěřřiitt ppookkuusseemm nnaa ddeessccee DDEE22,, aabbyycchhoomm ssee uujjiissttiillii,, žžee nnáámm pprraaccuujjee ii vv rreeááll--

nnéémm oobbvvoodduu,, aavvššaakk ddoobbrráá ssiimmuullaaccee zzkkrrááttíí nnaaššii ddoobbuu kkrroouužžeenníí vvee ssmmyyččccee ZnovuALépe ..

~ o ~