VHAD - Návod k VHDL hadovi Obsah Příklad č. 1 – Přepis informace ze vstupů (SW0 až SW3) na ledky (LEDG0 až LEDG3) ...................... 1 Příklad č. 2 – Blikající LED ..................................................................................................................... 3 Příklad č. 3 – Časovač 1s ......................................................................................................................... 4 Příklad č. 4 – Had 8 x LED GREEN (změna vždy po 1s, svítí 1 LED) ................................................... 5 Příklad č. 5 – Had 16 x LED RED (změna vždy po 1s, svítí 2 LED) ...................................................... 6 Příklad č. 6 – Had 16 x LED RED (změna vždy po 1s, svítí 3 LED, tam a zpět) ................................... 7 Příklad č. 7 – Modulární, snadno editovatelný, velmi přítulný had ......................................................... 8
Příklad č. 1 – Přepis informace ze vstupů (SW0 až SW3) na ledky (LEDG0 až LEDG3) LIBRARY ieee;USE ieee.std_logic_1164.all; ENTITY sw4led IS PORT ( SW: in std_logic_vector (3 downto 0); LEDG: out std_logic_vector (3 downto 0) ); END sw4led; ARCHITECTURE dataflow OF sw4led IS BEGIN LEDG <= SW; END dataflow; Jméno architektury se dle obecného zvyku volí vždy jen podle typu jejího popisu, zde tedy dataflow, což naznačuje, že obsahuje pouhý kombinační obvod Možné zápisy přepisu přepínačů na LEDR LEDG <= SW; přepisuje všechny deklarované bity LEDG(0) <= SW(0); přepisuje pouze SW[0] na LEDG[0] SW: in std_logic_vector (3 downto 0); deklarace vstupního 4-bitového vektoru LEDG: out std_logic_vector (3 downto 0); deklarace výstupního 4-bitového vektoru Blíže se o vektorech i v 5. Přenášce, snímek 41 až 48]
1
Pro deklaraci vektoru volte vždy jen směr downto - vektory se směrem to a downto jsou vzájemně nepřevoditelné – dají se převést jen kopírováním bit po bitu.
port ( A, B: in std_logic_vector (7 downto 0); Z: out std_logic_vector (1 to 16) );
Pokud definujete několik vektorů stejného rozsahu, můžete využívat i atributy, což je něco jako property v Javě.
SIGNAL x : std_logic_vector(31 downto 0); SIGNAL y : std_logic_vector(0 to 31); SIGNAL z1 : std_logic_vector(y'RANGE);
--(0 to 31)
SIGNAL z2 : std_logic_vector(0 to y'LENGTH-1); --(0 to 31) SIGNAL z3 : std_logic_vector(y'LOW to y'HIGH); --(0 to 31)
signal ex: std_logic_vector(11 downto 8); ex‘left ex‘right ex‘high ex‘low ex‘range ex‘reverse_range ex‘length
11 8 11 8 (11 downto 8) (8 to 11) 4
2
Příklad č. 2 – Blikající LED LIBRARY ieee;USE ieee.std_logic_1164.all; USE ieee.numeric_std.all; --knihovnu potrebujeme pro typ unsigned ENTITY blikajici_led IS PORT ( CLOCK_50 : IN STD_LOGIC; LEDG : OUT STD_LOGIC_VECTOR(0 downto 0) ); END blikajici_led; ARCHITECTURE rtl OF blikajici_led IS signal count : unsigned(25 downto 0); BEGIN process (CLOCK_50) begin if rising_edge(CLOCK_50) then count <= count + 1; end if; end process; LEDG(0) <= count(25); END rtl; Všimněte si, že komentáře ve VHDL kódu jsou vždy psané bez diakritiky – obvodové železo nemá rádo háčky a diakritice nepřeje…
3
Příklad č. 3 – Časovač 1s LIBRARY ieee;USE ieee.std_logic_1164.all; ENTITY Casovac_1s IS PORT ( CLOCK_50 : IN STD_LOGIC; LEDG : OUT STD_LOGIC_VECTOR(8 downto 8) ); END Casovac_1s; ARCHITECTURE rtl OF Casovac_1s IS CONSTANT MAX: INTEGER := 50000000/2-1; SIGNAL clockticks: INTEGER RANGE 0 TO max:=0; BEGIN ClocDivide:PROCESS(CLOCK_50) VARIABLE q2:std_logic:='0'; BEGIN IF rising_edge(CLOCK_50) THEN IF clockticks < MAX THEN clockticks <= clockticks + 1; ELSE clockticks <= 0; q2:=not q2; END IF; END IF; LEDG(8) <= q2; END PROCESS;
END rtl; Jméno architektury je zde opět zvoleno dle obecného zvyku, že jen specifikujeme způsob jejího popisu, zde tedy rtl – register transfer logic, což naznačuje, že obsahuje sekvenční obvod. Pro jména architektur se obvykle volí jen jedno ze čtyř jmén – structural, dataflow, rtl, nebo behavioral, poslední se používá skoro jako synonymom k rtl neboť značí, že architektura obsahuje popis chování obvodu.
4
Příklad č. 4 – Had 8 x LED GREEN (změna vždy po 1s, svítí 1 LED) LIBRARY ieee;USE ieee.std_logic_1164.all;USE ieee.numeric_std.all; ENTITY had_tam IS PORT ( CLOCK_50 : IN STD_LOGIC; LEDG : OUT STD_LOGIC_VECTOR(7 downto 0) ); END had_tam; ARCHITECTURE rtl OF had_tam IS signal registr : std_logic_vector(7 downto 0) := X"01"; signal tik : std_logic := '0'; BEGIN div: process (CLOCK_50) constant MAX: integer:=50000000-1; variable count: integer range 0 to MAX:=0; begin if rising_edge(CLOCK_50) then if count<MAX then count :=count+1; tik<='0'; else count:=0; tik <= '1'; end if; end if; end process; shift: process (tik) begin if rising_edge(tik) then registr <= registr(6 downto 0) & registr(7); end if; end process; LEDG <= registr; END rtl;
5
Příklad č. 5 – Had 16 x LED RED (změna vždy po 1s, svítí 2 LED) LIBRARY ieee;USE ieee.std_logic_1164.all;USE ieee.numeric_std.all; ENTITY had_tam16 IS PORT ( CLOCK_50 : IN STD_LOGIC; LEDR : OUT STD_LOGIC_VECTOR(15 downto 0) ); END had_tam16; ARCHITECTURE rtl OF had_tam16 IS signal registr : std_logic_vector(15 downto 0) := (1 downto 0=>'1', others=>'0'); -- X“0003“ -- "0000000000000011"; signal tik : std_logic := '0'; BEGIN div: process (CLOCK_50) constant MAX: integer:=50000000-1; variable count:integer range 0 to MAX:=0; begin if rising_edge(CLOCK_50) then if count<MAX then count :=count+1; tik<='0'; else count:=0; tik <= '1'; end if; end if; end process; shift: process (tik) begin if rising_edge(tik) then registr <= registr(14 downto 0) & registr(15); end if; end process; LEDR <= registr; END rtl;
6
Příklad č. 6 – Had 16 x LED RED (změna vždy po 1s, svítí 3 LED, tam a zpět) LIBRARY ieee;USE ieee.std_logic_1164.all;USE ieee.numeric_std.all; ENTITY had_tam16zpet IS PORT ( CLOCK_50 : IN STD_LOGIC; LEDR : OUT STD_LOGIC_VECTOR(15 downto 0)); END had_tam16zpet; ARCHITECTURE rtl OF had_tam16zpet IS signal registr : std_logic_vector(15 downto 0) := (2 downto 0=>'1', others=>'0'); -- "0000000000000111"; signal tik : std_logic := '0'; BEGIN div: process (CLOCK_50) constant MAX: integer:=50000000-1; variable count:integer range 0 to MAX:=0; begin if rising_edge(CLOCK_50) then if count<MAX then count :=count+1; tik<='0'; else count:=0; tik <= '1'; end if; end if; end process; shift: process (tik) variable dolu:BOOLEAN := FALSE; begin if rising_edge(tik) then if dolu then registr <= registr(0) & registr(15 downto 1); dolu:=registr(1)/='1'; -- registr je signal, na rozdil od promenne pri cteni obsahuje porad stejnou hodnotu, -- i kdyz se ta v procesu prepise. V registr(1) je tedy to, co po posunu bude -- v registr(0), viz prednaska 6 snimky str. 38 az 40 else registr <= registr(14 downto 0) & registr(15); dolu:=registr(14)='1'; end if; end if; end process; LEDR <= registr; END rtl;
7
Příklad č. 7 – Modulární, snadno editovatelný, velmi přítulný had V kódu se neustále opakuje dělič frekvence, což nemusí být šikovné, protože například pro simulaci musíme dělič vyřadit, protože není dobré simulovat dělení 50 miliony – to se tedy načekáte, než by se Vám něco objevilo na výstupním grafu. Chceme-li dělič udělat jako externí obvod, který je samostatně editovatelný, nabízí se komponenty vyložené na 6. přednášce na snímcích 64 až 73. Zde jsme si říkali, že komponenty se chovají podobně jako deklarace tříd a tvorba jejich instancí. Jako univerzální dělič, využijeme třeba nějaký dělič z přednášky 8, či si upravíme dělič z příkladu 2 na samostatný modul. Dělič z příkladu 2 přejmenujeme na Delic50e6, protože to je ta funkce, kterou ve skutečnosti provádí s obecným vstupem CLK. Změny v jeho kód jsou vyznačené červeně. LIBRARY ieee;USE ieee.std_logic_1164.all; ENTITY Delic50e6 IS PORT ( CLK : IN STD_LOGIC; Q : OUT STD_LOGIC ); END Delic50e6; ARCHITECTURE rtl OF Delic50e6 IS CONSTANT MAX: INTEGER := 50000000/2-1; SIGNAL clockticks: INTEGER RANGE 0 TO max:=0; BEGIN ClocDivide:PROCESS(CLK) VARIABLE q2:std_logic:='0'; BEGIN IF rising_edge(CLK) THEN IF clockticks < MAX THEN clockticks <= clockticks + 1; ELSE clockticks <= 0; q2:=not q2; END IF; END IF; Q <= q2; END PROCESS; END rtl; 8
Podobně upravíme i posledního hada z příkladu 6. Zrušíme v něm hodinový blok, a signál TIK nahradíme vstupem, který opět pojmenujeme CLK – tedy obecným jménem pro hodiny, a výstup pojmenujeme Q, tedy obecným výstupem, obvod již nebude Toplevel entity, ale vnořený, takže odkazy na jména z Pin Assignments nemají žádný význam. LIBRARY ieee;USE ieee.std_logic_1164.all;USE ieee.numeric_std.all; ENTITY had2tam16zpet IS PORT ( CLK : IN STD_LOGIC; Q : OUT STD_LOGIC_VECTOR(15 downto 0)); END had2tam16zpet; ARCHITECTURE rtl OF had2tam16zpet IS signal registr : std_logic_vector(15 downto 0) := (2 downto 0=>'1', others=>'0'); -- "0000000000000111"; --signal tik : std_logic := '0'; BEGIN --div: process (CLOCK_50) -- constant MAX: integer:=50000000-1; -- variable count:integer range 0 to MAX:=0; -- begin -if rising_edge(CLOCK_50) then -if count<MAX then count :=count+1; tik<='0'; -else count:=0; tik <= '1'; -end if; -end if; -- end process; shift: process (CLK) variable dolu:BOOLEAN := FALSE; begin if rising_edge(CLK) then if dolu then registr <= registr(0) & registr(15 downto 1); dolu:=registr(1)/='1'; -- registr je signal, na rozdil od promenne pri cteni obsahuje porad stejnou hodnotu, -- i kdyz se ta v procesu prepise. V registr(1) je tedy to, co po posunu bude -- v registr(0), viz prednaska 6 snimky str. 38 az 40 else registr <= registr(14 downto 0) & registr(15); dolu:=registr(14)='1'; end if; end if; end process; Q <= registr; END rtl; 9
Od nových obvodů Delic50e6.vhd a had2tam16zpet.vhd vytvoříme Symbol File pomocí známého postupu File -> Create/Update -> Create Symbol Files for Current File, které lze také volat i z kontextového menu souboru na záložce Files okna Project Navigator. Nyní vytvoříme Váš určitě oblíbený Block Diagram Schematic File, kterému dáme názvem například vhad.bdf. Do něho vložíme postupem, který znáte z kreslení schémat, oba nové bloky napsané ve VHDL.
K blokům připojíme vstupy a výstupy CLOCK_50 a LEDR. Oba bloky spojíme a spojovací vodič pojmenujeme pomocí kontextového menu vodiče, aby ve výsledném souboru, který brzy vytvoříme, měl smysluplné jméno. Zvolíme například název CLOCK_1s.
Výsledné schéma může vypadat asi takto Delic50e6 CLOCK_50
INPUT VCC
had2tam16zpet CLOCK_1s
CLK
Q
CLK
PIN_N2
inst
inst1
10
Q[15..0]
OUTPUT
PIN_AE23 PIN_AF23 PIN_AB21 PIN_AC22 PIN_AD22 PIN_AD23 PIN_AD21 PIN_AC21 PIN_AA14 PIN_Y13 PIN_AA13 PIN_AC14 PIN_AD15 PIN_AE15 PIN_AF13 PIN_AE13
LEDR[15..0]
Schéma vhad.bdf, vytvořené v symbolickém editoru, převedeme nazpátek na VHDL kód. Volíme opět postup File -> Create/Update -> ale tentokrát ->Create HDL Design File for Current File.
Vytvořený soubor VHAD.VHD se nám neobjeví v nabídce Files, protože obsahuje stejnou entitu jako VHAD.BDF, a můžeme překládat pouze jeden z nich. Přidáme si tedy VHAD.VHD do seznamu souborů ručně, přes kontextové menu záložky Files okna Projekt navigator
Po přidání VHAD.VHD odstraníme ze seznamu na záložce Files původní soubor VHAD.BDF pomocí klávesy Delete – soubor se tím nezruší, pouze zmizí ze seznamu překládaných souborů. Z nového VHAD.VHD uděláme Top-level Entitu. Můžeme ho přeložit a nahrát. Funguje zcela jako původní had z příkladu 6. 11
LIBRARY ieee; USE ieee.std_logic_1164.all; LIBRARY work; -- knihovna obsahujici soubory vytvorene projektem ENTITY vhad IS PORT( CLOCK_50 : IN STD_LOGIC; LEDR : OUT STD_LOGIC_VECTOR(15 DOWNTO 0) ); END vhad; ARCHITECTURE bdf_type OF vhad IS COMPONENT delic50e6 -- komponenta, tedy neco jako deklarace tridy PORT(CLK : IN STD_LOGIC; Q : OUT STD_LOGIC ); END COMPONENT; COMPONENT had2tam16zpet PORT(CLK : IN STD_LOGIC; Q : OUT STD_LOGIC_VECTOR(15 DOWNTO 0) ); END COMPONENT; SIGNAL CLOCK_1s : STD_LOGIC; --pojmenovany spojovaci vodic BEGIN b2v_inst : delic50e6 -- instance prvni tridy PORT MAP(CLK => CLOCK_50, Q => CLOCK_1s); b2v_inst1 : had2tam16zpet --instance druhe tridy PORT MAP(CLK => CLOCK_1s, Q => LEDR); END bdf_type; Trocha námahy věnované externímu propojení se nám do budoucna bohatě vyplatí v mnoha hodinách ušetřeného času. Můžeme teď psát nezávislé malé bloky, které jsou mnohem přehlednější a dají se snadno samostatně testovat. Jelikož máme stále schovaný originální soubor VHAD.BDF, ze kterého jsme VHAD.VHD vygenerovali, tak propojeni bloků můžeme kdykoliv upravit, doplnit nové části, či zrušit nevhodné kusy. Lze také vytvořit i několik různých propojení bloků, třeba pro testování v simulaci, pro předvádění, apod. Zkušenější psavci mohou i přímo upravovat vytvořený propojovací soubor, přidávat od něho ručně komponenty, prostě s ním pracovat jako s kterýmkoliv VHDL souborem.
Dobré naladění na hadění přejí Vaši učitelé 12