Proces

V jeziku VHDL lahko opisujemo vezje na ravni obnašanja (angl. behavior), kjer nam za opis vezja ni potrebno poznati strukture vezja. Obnašanje vezja določa algoritem v obliki zaporedja stavkov, ki so podobni stavkom običajnih programskih jezikov (npr. if, case...). Opis obnašanja vezja je podoben programiranju v običajnih programskih jezikih. Zaporedne stavke pišemo v jeziku VHDL znotraj posebnega okolja (npr. procesa ali procedure...), ki omogoča prirejanje vrednosti ali izraza nekemu signalu na več mestih. V takšnem primeru je vrstni red zapisa stavkov pomemben in izvede se zadnja prireditev. Spoznali bomo procese s katerimi opisujemo:

  1. obnašanje kombinacijskih vezij,
  2. osnovne sekvenčne gradnike,
  3. sekvenčna vezja z registrom stanj.

2.4 Opis obnašanja kombinacijskih vezij

Znotraj procesa lahko opisujemo obnašanje kombinacijskih vezij s pogojnimi (if) stavki in prireditvenimi stavki. V pogojnem stavku za besedo then zapišemo stavke, ki se izvršijo, ko je pogoj izpolnjen, za else pa stavke, ki se izvršijo ob neizpolnjenem pogoju. Pogojni stavek zaključimo z end if.

Pogojni stavek

if pogoj then
  zaporedni stavki;
else
  zaporedni stavki;
end if;
  if pogoj1 then
    zaporedni stavki;
  elsif pogoj2 then
    zaporedni stavki;
    ...
  else
    zaporedni stavki;
  end if;

Kadar imamo več zaporednih (povezanih) pogojev, jih zapišemo z if...elsif...else obliko pogojnega stavka. V takšnam stavku imajo pogoji, ki so zapisani prej, prednost pred tistimi, ki so zapisani kasneje.
Stavek else lahko tudi izpustimo, vendar moramo v primeru opisa kombinacijskih vezij poskrbeti, da bodo izhodi definirani pri vseh kombinacijah na vhodih. V praksi to naredimo tako, da signalu priredimo privzeto vrednost pred if stavkom.

Proces je okolje, ki vsebuje zaporedje stavkov, zapisanih med rezerviranima besedama begin in end process. Opis procesa se začne z oznako, sledi ji rezervirana beseda process in v oklepaju seznam vhodnih signalov. Simulator izvede stavke v procesnem okolju vsakokrat, ko se spremeni vrednost kateregakoli signala iz seznama signalov, na katere je občutljiv.

Procesni stavek

OZNAKA: process (seznam)
begin
    zaporedni stavki;
end process;

seznam: vhodni signali, na katere je proces občutljiv

Poglejmo si primer dveh pravilnih in enega napačnega opisa kombinacijskega vezja, ki določa odprtost ventila ('1' ali '0') glede na stanje pretoka, s signalom stop pa v vsakem primeru postavimo ventil na '0'. Vrednost na signalu ventil se lahko spremeni, če se spremeni eden od signalov pretok ali stop, zato ta dva signala navedemo v seznam pri procesu. V prvih dveh primerih (p1 in p2) je signal ventil definiran pri vseh vhodnih kombinacijah. Tretji proces pa ne določa vrednosti signala ventil kadar nobeden izmed pogojev ni izpolnjen. V tem primeru mora signal ventil ohranjati zadnjo vrednost, zato proces p3 ne predstavlja kombinacijsko vezje!

PravilnoPravilnoNapačno
  p1: process (pretok, stop)
  begin
    if pretok > 10 then
      ventil <= '1';
    else
      ventil <= '0';
    end if;
    if stop='1' then
      ventil <= '0';
    end if;
  end process;
  p2: process (pretok, stop)
  begin
    ventil <= '0';
    if pretok > 10 then
      ventil <= '1';
    end if;
    if stop='1' then
      ventil <= '0';
    end if;
  end process;
  p3: process (pretok, stop)
  begin
    if pretok > 10 then
      ventil <= '1';
    end if;
    if stop='1' then
      ventil <= '0';
    end if;
  end process;

3.2 Osnovni gradniki sekvenčnih vezij

Pogledali si bomo načrtovanje sinhronih sekvenčnih vezij, ki preklapljajo izhode ob fronti urinega signala. Sinhrona sekvenčna vezja opišemo s sinhronim procesom. Proces je struktura v kateri lahko uporabljamo sekvenčne stavke: prireditveni stavek, pogojni stavek..., pri katerih je vrstni red v določenih primerih pomemben (npr. med več prireditvami istemu signalu se izvede le zadnja). Pri opisu sinhronih sekvenčnih vezij zapišemo vse stavke znotraj pogoja za fronto ure rising_edge(clk) ali falling_edge(clk).

Sinhroni proces I

oznaka: process (clk)
begin
  if rising_edge(clk) then
    zaporedni stavki;
  end if;
end process;

Sinhroni proces I je struktura, ki jo bomo uporabljali za opis sinhronih sekvenčnih vezij. Kadar uporabljamo v opisu digitalnih sistemov več procesov, moramo vsakemu procesu prirediti svojo unikatno oznako. Simulacija sinhronega procesa naj se izvrši le ob spremembi ure (signala clk), ki jo navedemo v oklepaju za rezervirano besedo process.

Kako deluje procesni stavek

Običajni stavki v jeziku VHDL predstavljajo dele vezja in njihov vrstni red pri opisu vezja ni pomemben. Ker jih simulator obravnava tako, kot da se izvajajo vsi hkrati, jih imenujemo tudi sočasni stavki. Procesni stavek je eden izmed sočasnih stavkov - če je v opisu vezja več procesnih stavkov, jih simulator izvaja sočasno. Običajni stavki se med simulacijo izvedejo takrat kadar se spremeni kateri izmed vhodov, procesni stavki pa se izvedejo, če se spremeni kateri izmed signalov, ki so našteti za rezervirano besedo process.

Znotraj procesnega stavka pa imamo zaporedne stavke. Zaporedni stavki se izvajajo v takšnem vrstnem redu, kot so zapisani (podobno kot pri običajnih programskih jezikih). Primer zaporednih stavkov sta pogojni stavek (if) in izbirni stavek (case), ki se lahko uporabljata samo znotraj procesnega okolja. Tudi prireditveni stavki se znotraj procesnega okolja obnašajo kot zaporedni stavki.

Primer:

  x <= "1010";
  ....
  x <= "0011";

Znotraj procesnega stavka lahko signalu na več mestih priredimo vrednost. Končna vrednost signala bo tista, ki je bila prirejena nazadnje (v našem primeru "0011").

Takšen zapis izven procesnega okolja ni dovoljen, ker vsak prireditveni stavek predstavlja izhod iz dela vezja. V tem primeru bi bila dva izhoda vezana skupaj, kar pa lahko storimo samo pri opisu tristanjskih vodil. Prav tako ne smemo prirediti vrednost istemu signalu v dveh ali več procesnih stavkih!

Sinteza sekvenčnih vezij

Procesni stavek uporabljamo za opis kombinacijskih in sekvenčnih vezij. Pri opisu sekvenčnih vezij moramo upoštevati nekaj pravil če želimo narediti avtomatsko sintezo vezja iz visokonivojskega zapisa.

1. Sekvenčni gradniki opisani z enim procesnim stavkom imajo izhode vezane samo na eno uro, ki deluje s prvo ali z zadnjo fronto. Če delamo asinhrono vezje, kjer so sekvenčni gradniki proženi z različnimi urami, moramo napisati več procesnih stavkov, tako da je v vsakem procesnem stavku samo en urin signal.

Primer: V vezju potrebujemo dve uri: clk1 in clk2

Napačen zapis


 P: process (clk1, clk2)
 begin
   if rising_edge(clk1) then
     p <= a;
   end if;
   if rising_edge(clk2) then
     q <= p;
   end if;
 end process;
Pravilen zapis


 P1: process (clk1)
 begin
   if rising_edge(clk1) then
     p <= a;
   end if;
 end process;

 P2: process (clk2)
 begin
   if rising_edge(clk2) then
     q <= p;
   end if;
 end process;

2. Program za sintezo vezij vedno naredi sekvenčne gradnike z uporabo D flip-flopov, ki so proženi na prvo ali na zadnjo fronto ure. Opis sekvenčnih gradnikov vedno izhaja iz opisa flip-flopa.

Primer: Sekvenčna vezja brez reset signala ali s sinhronim resetom

 FF: process (clk)
 begin
   if rising_edge(clk) then
    stavki...
   end if;
 end process;

Vsi stavki so napisani znotraj pogojnega stavka, ki določa proženje ure. Uporabimo lahko prireditvene stavke, pogojne stavke (if), izbirne stavke (case), ne smemo pa ponovno uporabiti pogoja za fronto ure, ki bi zahteval od programa za sintezo uporabo flip-flopa z več urami (tak gradnik preprosto ne obstaja).


 Flip-flop

Osnovni gradnik sinhronih vezij je D flip-flop. Flip flop ali register, ki ob fronti ure prenese na izhod vrednost iz vhoda opišemo s preprostim prireditvenim stavkom znotraj sinhronega procesa.

library IEEE;
use IEEE.std_logic_1164.all;

entity dff is
  port ( vhod: in std_logic;
         clk: in std_logic;
         izhod: out std_logic );
end dff;

architecture opis of dff is
begin
  p: process (clk)
  begin
    if rising_edge(clk) then
      izhod <= vhod;
    end if;
  end process;
end opis;

Flip-flopi in registri imajo pogosto tudi reset vhod, s katerim postavimo izhod na vrednost 0. Vhod za resetiranje je lahko asinhroni (izhod se postavi na 0 takoj ob prisotnosti reset signala) ali pa sinhroni (izhod se postavi na 0 ob prisotnosti reset signala in prvi fronti urinega signala). Sekvenčne gradnike z asinhronim reset signalom opišemo znotraj strukture sinhroni proces II.

Sinhroni proces II

oznaka: process (clk, reset)
begin
  if reset='1' then
    priredi začetno vrednost;
  elsif rising_edge(clk) then
    zaporedni stavki;
  end if;
end process;

Sinteza sekvenčnih vezij II

Za opis sekvenčnih vezij, ki imajo asinhroni set ali reset, uporabimo kot osnovo flip-flop z asinhronim reset signalom.

Primer: Sekvenčna vezja z asinhronim reset signalom

 FF: process (clk)
 begin
   if reset='1' then
    inicialitacija signalov...
   elsif rising_edge(clk) then
    stavki...
   end if;
 end process;

Pri inicializaciji postavimo signale na logično ničlo ali enico, ki mora biti konstantna vrednost (npr. ne smemo signalu dodeliti vrednost nekega drugega signala, ki ni konstanta med prevajanjem).

Jedro opisa sekvenčnega gradnika se ponovno nahaja znotraj pogojnega stavka, ki določa proženje ure. Uporabimo lahko prireditvene stavke, pogojne stavke (if), izbirne stavke (case), ne smemo pa ponovno uporabiti funkcije za fronto ure, ki bi zahtevala od programa za sintezo uporabo flip-flopa z več urami (tak gradnik ne obstaja).

Asinhroni reset (ali set) je dober način da postavimo vezje v začetno stanje, vendar moramo biti previdni pri izvoru reset signala. Za pravilno delovanje vezja moramo zagotoviti, da je asinhroni reset signal brez motenj. Če dobimo reset signal s kombinacijsko logiko, se lahko zgodi, da bomo dobili na tem signalu špičke, ki so posledica zakasnitev v vezju. Izvor asinhronega reset signala naj bo zato čist zunanji signal, ali pa signal z izhoda flip-flopa.

Arhitektura DFF z asinhronim resetomArhitektura DFF s sinhronim resetom
architecture opis2 of dff is
begin
  p: process (clk, reset)
  begin
    if reset='1' then
      izhod <= '0';
    elsif rising_edge(clk) then
      izhod <= vhod;
    end if;
  end process;
end opis2;
architecture opis3 of dff is
begin
  p: process (clk)
  begin
    if rising_edge(clk) then
      if reset='1' then
        izhod <= '0';
      else
        izhod <= vhod;
      end if;
    end if;
  end process;
end opis3;

Pri flip-flopu z asinhronim reset signalom moramo dati reset v seznam signalov, na katere je procesni stavek občutljiv. Asinhroni reset ima prednost pred uro, zato ga zapišemo kot prvi pogoj v pogojnem stavku.


 Register

Registre opišemo z enakimi strukturami kot flip-flope, le da uporabimo za signala vhod in izhod vektorski podatkovni tip. Poznamo registre brez reseta, registre z asinhronim in registre s sinhronim reset signalom. Registri imajo pogosto tudi dodaten vhod (angl. CE - clock enable) za omogočanje vpisa podatka.

library IEEE;
use IEEE.std_logic_1164.all;

entity reg8 is
  port ( d: in std_logic_vector(7 downto 0);
         clk: in std_logic;
         ce: in std_logic;
         q: out std_logic_vector(7 downto 0) );
end reg8;

architecture opis of reg8 is
begin
  p: process (clk)
  begin
    if rising_edge(clk) then
      if ce='1' then
        q <= d;
      end if;
    end if;
  end process;
end opis;

3.3 Sekvenčna vezja z registrom stanj

Sinhrona sekvenčna vezja imajo pogosto vgrajeno povratno zanko med izhodom iz registra in njegovim vhodom. Povratna zanka omogoča opis vezij, pri katerih je naslednje stanje odvisno od vhodov in trenutnega stanja.


 Števec

Dvojiški števec dobimo tako, da izhod iz registra ob vsakem urinem impulzu povečamo za 1. Deklarirali bomo notranji vektor st in mu določili začetno stanje ("0000") od katerega naprej bo začel šteti. Podatkovni tip vektorja naj bo unsigned, ker ima v knjižnici IEEE.numeric_std definirano operacijo seštevanja, ki jo uporabimo za prištevanje enice.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity stevec is
  port ( clk: in std_logic;
         ce: in std_logic;
         izhod: out std_logic_vector(3 downto 0) );
end stevec;

architecture opis of stevec is
  signal st: unsigned(3 downto 0) := "0000";
begin
  p: process (clk)
  begin
    if rising_edge(clk) then
      if ce='1' then
        st <= st + 1;
      end if;
    end if;
  end process;

izhod <= std_logic_vector(st);
end opis;

Opis števca je narejen s strukturo sinhroni proces I, kjer smo prištevanje vrednosti zapisali znotraj dodatnega pogoja za omogočanje štetja (signal ce, angl. count enable).


 Avtomat

Delovanje sekvenčnega avtomata predstavimo z diagramom prehajanja stanj. Poglejmo si avtomat za detekcijo pritiska tipke.Ob pritisku na tipko, gre avtomat iz mirovnega stanja v stanje impulz, ob naslednjem urinem ciklu pa v stanje čakaj, kjer ostane tako dolgo, dokler je tipka pritisnjena. Avtomat v stanju impulz generira izhodni signal, ki je dolg natanko eno urino periodo.


Za zapis stanj avtomata v jeziku VHDL definiramo nov podatkovni tip, v katerem naštejemo vsa možna stanja.

Naštevni tip podatkov

Deklaracija:
type ime_tipa is (ime1, ime2, ime3...);
signal ime_signala: ime_tipa;

Prireditveni stavek:

ime_signala <= ime1;

Kodiranje stanj

V visokonivojskem opisu avtomatov uporabljamo simbolična imena za posamezna stanja, ki jih definiramo v naštevnem podatkovnem tipu. Program za sintezo vezja mora opraviti kodiranje stanj, pri katerem dodeli binarne kombinacije posameznim stanjem.

Običajno se uporablja binarno kodiranje (stanja predstavljajo zaporedne dvojiške vrednosti) ali pa kodiranje z eno enico v zapisu vsakega stanja (angl. "one hot"). V prvem primeru potrebujemo najmanj bitov in kompleksnejšo logiko za izbiro naslednjega stanja, v drugem pa je register daljši, kombinacijski del pa enostavnejši. Način kodiranja stanj izberemo v programu za sintezo.

Primer: Avtomat s tremi stanji (mir, impulz, cakaj)

Stanje
Binarno
One-hot
mir
00
001
impulz
01
010
cakaj
10
100

Pri kodiranju stanj nismo uporabili vseh možnih kombinacij, zato je zelo pomembno da definiramo v katero stanje bo šel avtomat, če se znajde v eni izmed neuporabljenih kombinacij. Najbolje je, če pri določanju prehodov med stanju uporabimo when others za definiranje zadnjega izmed naštetih stanj.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

entity avtomat is
  port ( clk: in std_logic;
         tipka: in std_logic;
         izhod: out std_logic );
end avtomat;

architecture opis of avtomat is
  type vsa_stanja is (mir, impulz, cakaj);
  signal stanje: vsa_stanja;
begin
  sekv: process (clk)
  begin
  if rising_edge(clk) then
    case stanje is
      when mir =>
        if tipka='1' then
          stanje <= impulz;
        end if;

      when impulz =>
        stanje <= cakaj;

      when others =>
        if tipka='0' then
          stanje <= mir;
        end if;
    end case;
  end if;
  end process;

  komb: process (stanje)
  begin
    if stanje=impulz then
      izhod <= '1';
    else
      izhod <= '0';
    end if;
  end process;
end opis;

Osnovni stavki Strukturni opis