• Nem Talált Eredményt

Konstansok, változók, jelek, és generic használata

2. Programozható logikai kapuáramkörök,

2.2. Bevezetés a VHDL nyelv használatába

2.2.8. Konstansok, változók, jelek, és generic használata

A VHDL kód sok helyen tartalmazhat konstans kifejezéseket és akár tömb határolókat. Egy jó tervezési koncepció lehet – hasonlóan más programnyelvekhez – ha a sokszor használt kons-tans kifejezéseket szimbolikus névvel definiáljuk, és ott adunk hozzá értéket is. A definiált konstansok az előfeldolgozás során értékelődnek ki és helyettesítődnek, ezáltal nem igényel-nek fizikai erőforrásokat. A konstansok deklarációját az entitáshoz tartozó architektúra leírás deklarációs részében kell megadni, még az első használat előtt, amelynek szintaxisa a követ-kező:

constant konstans_neve : adattípus : = kezdőérték;

Példaként a következő konstans deklarációk adottak, amelyeket tömbök határainak, vagy logikai vektor kifejezések bitszélességének megadásákor lehet felhasználni:

constant ADAT_BIT: integer : = 8;

constant ADAT_TARTOMANY: integer : = 2** ADAT_BIT - 1;

-- még néhány példa a használatukra: egesz, valós és fizikai típus -- deklarációkra

constant byteok_szama : integer := 4;

constant bitek_szama : integer := 8* number_of_bytes;

constant e : real := 2.718281828;

constant jelterjedesi_kesleltetes : time := 3 ns;

constant size_limit, count_limit : integer := 255;

Feladat 2/a – konstansok használata

Definiáljunk konstansokat egy 4-bites összeadó (neve osszeado_4_bit) áramkörben a bitszé-lesség megadásához, amelyben a numberic_std csomagot használja az ’+’ operátorához.

A bemeneti operandusok (a_in, b_in) legyenek 4-bit szószélességű std_logic_vector típusúak, a kimeneti eredmény legyen 4-bit szélességű std_logic_vector típusú, és az átvitel (c_out – carry out) 1-bites std_logic típusú. Mivel az ’+’ összeadás operátora a numeric_std csomagon értelmezett unsigned adattípusra érvényes, ezért a belső jelek, és a külső portok jelei között explicit típus konverzió is szükséges. Az ADAT_BIT nevű szimbolikus konstans szolgál arra, hogy az architektúra belső jeleit 4+1-bites szószélességen definiáljuk (előjel kiterjesztés végett a +1 bit). Egy fontos szabály, hogy két pl. N-bites szám összege helyesen egy N+1 bites eredményként tárolható csak el.

-- 4-bites összeadó library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all; -- ’+’ operátorához

entity osszeado_4_bit is port(

a_in, b_in: in std_logic_vector(3 downto 0);

c_out: out std_logic;

sum_out: out std_logic_vector(3 downto 0) );

end osszeado_4_bit;

architecture behav of osszeado_4_bit is

constant ADAT_BIT: integer := 4; --4-bites konstans kifejezés --belső jelek

signal a_sig, b_sig, sum_sig: unsigned(ADAT_BIT downto 0);

begin

a_sig <= unsigned('0' & a_in); --kiterjesztes elojel nelkul b_sig <= unsigned('0' & b_in);

sum_sig <= a_sig + b_sig; --osszeadas unsigned jeleken --eredmeny visszalakitasa (ADAT_BIT) szélességűre

sum_out <= std_logic_vector(sum_sig(ADAT_BIT-1 downto 0));

--eredmeny MSB bitje lesz a generalt carry out, atvitel c_out <= sum_sig(ADAT_BIT);

end behav;

Változók (variables)

A VHDL kód sok helyen tartalmazhat változó (variable) objektumokat, amelyeket első hasz-nálatuk előtt mindenképpen deklarálni kell. A változó azonban a kezdeti értékadás után (szemben a jellel) bármikor megváltoztathatja értékét. A változókat folyamatban vagy alprog-ramban adatok ideiglenes tárolására használják A változók deklarációját az entitáshoz tartozó architektúra leírás szekvenciális folyamatának (process) deklarációs részében (esetleg a nem tárgyalt eljárásban – procedure) lehet megadni, amelynek szintaxisa a következő:

variable valtozo_neve : adattípus : = kezdőérték;

Ha a változónak kezdeti értéket adunk, azonnal kiértékelődik. Ha kezdeti értéket nem adunk meg, akkor a változó az adott típus legkisebb értéke lesz (növekvő sorrendbe rendezett tarto-mányban), illetve legnagyobb eleme lesz (csökkenő sorrendű tartományban). Példaként a következő néhány változó deklarációk adottak:

variable index : natural := 0;

variable osszeg, atlag : real := 0.0;

variable start, befejezes : time := 0 ns;

Változók esetén is – hasonlóan a konstans kifejezésekhez, és a generichez – az értékadás operátora ’:=’. A változók a folyamat egy állapotát reprezentálják.

Következő kódrészlet a változók használatára mutat be egy rövid példát:

library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;

entity valtozo is end entity valtozo;

architecture behav of valtozo is constant incr : integers := 1;

begin process is

-- ide kerülhetnek a lokális változó deklarációk variable sum : integer := 0;

begin

sum := sum + incr;

end process;

end architecture behav;

Jelek (signals):

A jelek működésének megértéséhez a következő fontos alapfogalmakat kell tisztázni: ese-mény, meghajtó illetve lebonyolítás, vagy tranzakció.

Amikor egy jel értéke megváltozik, akkor egy ún. esemény (event) történik a jelen. Ami-kor egy értéknek egy jelhez egy bizonyos késleltetéssel (pl. after klauzula) való hozzárendelése időzítésre került, azt a jel meghajtóján (driver) elkezdődött lebonyolításnak (transaction) nevezik. Az is lebonyolítás, amely nem változtatja meg a jel értékét, ezért nem okoz eseményt a jelen. Új lebonyolítás nem kezdődik el a jelen, amíg az előző nem fejeződött be.

Az információ átadás szempontjából a legfőbb eltérés a jelek és a változók között, hogy a változók nem vihetnek át információt azon VHDL blokkon kívülre, amelyen belül deklará-ciójuk történt. Éppen ezért jelen jegyzetben kerüljük a változók, és a megosztott változók használatát. Ezekről részletesen más könyvekben, segédletekben [ASHENDEN], [KERESZTES] lehet olvasni. A jeleket az entitáshoz tartozó architektúra leírások deklarációs részén kell bevezetni, ezáltal a jelek nemcsak az egyidejű hozzárendelésekben, hanem a sorrendi hozzá-rendelésekben (process-en belül) is használhatóak. Másik fontos tulajdonság, hogy a jel nem azonnal értékelődik ki, hanem csak bizonyos (delta) késleltetéssel később vehet fel új értéket, míg a változó azonnal megkapja az értékét (sőt mint láttuk értéket is tárol egyben). Jelek esetén a hozzárendelést a ’<=’ szimbólummal adhatjuk meg, a jel nem tárol értéket, csak késleltet(het)i azt. A jel és a változó feldolgozásban további különbség, hogy a szekvenciális végrehajtású VHDL kódrészeken a feldolgozás sorról-sorra halad, ezért nevezik sorrendi VHDL-nek, míg az egyidejű/konkurens VHDL kódrészeken a sorokat csak akkor dolgozzák fel, ha egy esemény megjelent a jelek érzékenységi listáján. A jelekhez új értéket egyedi késleletetéses módon is adhatunk (pl. after kulcsszóval):

signal y : std_logic := ’0’;

. . .

-- egyedi késleltetés nélkül y <= not a;

. . .

-- egyedi késleltetéssel y <= not a after 5 ns;

Ebben a VHDL leírásban az y a hozzárendelés végrehajtásától számított 5 ns múlva veszi fel új értékét (not a), az after klauzula használatával. A késleltetés egyrészt tekinthető szintézis jelleggel a véges jelterjedési idő értékeként, azaz amikor a kimenet a bemenet válto-zásának hatására 5 ns késleltetéssel veszi fel új értékét. Másrészt vizsgálhatjuk szimulációs értelemben is, amikor a PC-n futó szimulátor belső, ciklus-pontos órájához képest felvett időzítést adjuk meg. A jelek és változók összehasonlításáról a későbbi 2.3.2. alfejezetben még részletesen olvashatunk, a folyamatok (process-ek) végrehajtása során.

Generikusok

Az előző Feladat 2/a akkor lenne tetszőlegesen konfigurálható, amennyiben az entitások portlistájában lévő bitszélességeket is konstansként lehetne definiálni. Erre az ’általánosításra’

a VHDL-ben a generikusok, azaz „generic” kulcsszó alkalmazásával van lehetőség, amely egyrészt entitások portlistájában szereplő port-oknak, másrészt az architektúra leírásokban példányosítandó komponenseknek is adhat át értéket. A generikusokat az entitás deklarációs részén lehet módosítani, vagy akár egy külső állományban (pl. egy felhasználó által készített egyedi csomagban) lehet megadni, amelyet meghívunk az adott entitásban. Ezáltal sokkal jobban modularizálható, skálázható VHDL leírásokat kaphatunk. Fontos megjegyezni azon-ban, hogy a ’generic’ új értéket az architektúra leírás törzsén belül már nem kaphat. A generic deklarációja a következő:

entity entitas_nev is generic (

generic_nev : adat_tipus : = alap_ertek(ek);

generic_nev : adat_tipus : = alap_ertek(ek);

. . .

generic_nev : adat_tipus : = alap_ertek(ek) )

port (

port_nev : mod adat_tipus;

. . . );

end entitas_nev;

Feladat 2/b – Generikusok használata

Az előző Feladat 2/a (ADAT_BIT = 4-bites összeadó áramkör) módosítása a ’generic’ kulcs-szó használatával a következő (a generic-el kibővített forrás neve legyen

osszeado_4_bit_gen):

-- 4-bites összeadó generic-el library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all; -- ’+’ operátorához

entity osszeado_4_bit_gen is

generic (ADAT_BIT : integer := 4); -- generic megadása 4 adat-bitre port(

a_in, b_in: in std_logic_vector(ADAT_BIT-1 downto 0);

c_out: out std_logic;

sum_out: out std_logic_vector(ADAT_BIT-1 downto 0) );

end osszeado_4_bit_gen;

architecture behav of osszeado_4_bit_gen is --belső jelek

signal a_sig, b_sig, sum_sig: unsigned(ADAT_BIT downto 0);

begin

a_sig <= unsigned('0' & a_in); --kiterjesztes elojel nelkul b_sig <= unsigned('0' & b_in);

sum_sig <= a_sig + b_sig; --osszeadas unsigned jeleken -- eredmeny visszalakitasa (ADAT_BIT) szélességűre

sum_out <= std_logic_vector(sum_sig(ADAT_BIT-1 downto 0));

--eredmeny MSB bitje lesz a „generalt” carry out, atvitel c_out <= sum_sig(ADAT_BIT);

end behav;

Ha a fenti példában szereplő ADAT_BIT szélességű összeadót eggyel magasabb hierarchia szinten lévő entitásban komponensként kívánjuk példányosítani, akkor a kívánt ’generic’

értéket (itt bitszélességet) a példányosításnál meg kell adnunk. Ha a példányosításnál nem adunk meg, vagy elfelejtünk megadni generic értéket, akkor a bitszélességhez azt a kezdő értéket rendeli a fordító, amely az alacsonyabb hierarchia szinten lévő entitásban lett deklarál-va. A következő kódrészlet a korábbi osszeado_4_bit_gen összeadó áramkör néhány különböző tetszőlegesen definiált bitszélesség szerinti példányosítását szemlélteti (ahol ADAT_BIT=8-, 16-, valamint 4-bites alapértéket beállítva):

library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;

. . .

--bemeneti jelek

signal a_4, b_4, osszeg_4: unsigned(3 downto 0);

signal a_8, b_8, osszeg_8: unsigned(7 downto 0);

signal a_16, b_16, osszeg_l6: unsigned(l5 downto 0);

signal carry_4, carry_8, carry_16: std_logic;

-- osszeado peldanyosítasa 8-bitesként osszeado_8: work.osszeado_4_bit_gen(behav) generic map (ADAT_BIT => 8)

port map(a_in=>a_8, b_in=>b_8, c_out=>carray_8, sum_out=>osszeg_8)) ;

-- osszeado peldanyosítasa 16-bitesként osszeado_16: work.osszeado_4_bit_gen(behav) generic map (ADAT_BIT => 16)

port map(a_in=>a_l6, b_in=>b_16, c_out=>carry_16 , sum_out=>osszeg_l6)) ;

-- osszeado peldanyosítasa alapértéken, 4-bitesként osszeado_4: work.osszeado_4_bit_gen(behav)

-- itt nem adjuk meg a generic map-el a bitszelesseget!! -> alapertek port map(a_in=>a_4, b=>b_in_4, c_out=>carry_4, sum_out=>osszeg_4)) ;

A fenti esetekben a példányosítás során a generic map kulcsszót kell használnunk, ha a genericnek egy új, tetszőleges kezdőértéket kívánunk megadni.