Sunteți pe pagina 1din 43

Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 1

6. INSTRUCłIUNI SECVENłIALE ŞI CONCURENTE ÎN


LIMBAJUL VHDL

O descriere în limbajul VHDL are două domenii: un domeniu secvenŃial şi un domeniu concurent.
Domeniul secvenŃial este reprezentat de un proces sau subprogram care conŃine instrucŃiuni secvenŃiale. Aceste
instrucŃiuni sunt executate în ordinea în care apar în cadrul procesului sau subprogramului, ca şi în cazul
limbajelor de programare. Domeniul concurent este reprezentat de o arhitectură, care conŃine procese, apeluri
concurente de proceduri, asignări concurente ale semnalelor şi instanŃieri de componente (descrise în capitolul
8). Toate activităŃile descrise de acestea au loc simultan.
În această lucrare se prezintă formatul şi modul de utilizare al unor instrucŃiuni secvenŃiale şi
concurente. Pentru exemplificare sunt descrise unele componente combinaŃionale şi secvenŃiale de bază, ca de
exemplu multiplexoare, codificatoare, decodificatoare, bistabile, registre şi numărătoare.

6.1. InstrucŃiuni secvenŃiale


În această secŃiune se descriu mai întâi unele aspecte legate de procese, cum sunt modul de specificare a
unui proces, execuŃia unui proces, instrucŃiunea wait şi deosebirea dintre procesele combinaŃionale şi cele
secvenŃiale. Sunt prezentate apoi instrucŃiunile secvenŃiale care pot apare într-un proces sau subprogram:
asignarea secvenŃială a semnalelor, asignarea variabilelor, instrucŃiunea if, instrucŃiunea case, instrucŃiunile de
buclare (loop, while loop, for loop, next, exit) şi instrucŃiunea assert secvenŃială. Pe lângă acestea,
mai există instrucŃiunea secvenŃială de apel a unei proceduri şi instrucŃiunea de revenire dintr-o procedură sau
funcŃie. Acestea din urmă vor fi prezentate în capitolul 9 în care se descriu subprogramele.

ObservaŃii
• În exemplele care vor fi prezentate în continuare, se face referire la instrucŃiunile secvenŃiale din cadrul
proceselor. MenŃionăm că aceleaşi instrucŃiuni pot apare şi în cadrul subprogramelor (procedurilor şi
funcŃiilor).
• DeclaraŃia unui proces este prezentată în cadrul instrucŃiunilor secvenŃiale pentru a putea utiliza
procesele la exemplificarea acestor instrucŃiuni. Această declaraŃie reprezintă însă o instrucŃiune
concurentă, deoarece un proces este executat în paralel cu alte procese şi instrucŃiuni concurente.

6.1.1. Procese
Un proces este o secvenŃă de instrucŃiuni care sunt executate în ordinea specificată. DeclaraŃia unui
proces delimitează un domeniu secvenŃial al arhitecturii în care apare declaraŃia. Procesele se utilizează pentru
descrieri funcŃionale.

6.1.1.1. Structura şi execuŃia unui proces

Un proces poate apare oriunde în corpul unei arhitecturi (partea care începe după cuvântul cheie
begin). Structura de bază a declaraŃiei unui proces este următoarea:
[nume:] process [(listă_de_sensibilitate)]
[declaraŃii_de_tipuri]
[declaraŃii_de_constante]
[declaraŃii_de_variabile]
[declaraŃii_de_subprograme]
begin
instrucŃiuni_secvenŃiale
end process [nume];
2 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

DeclaraŃia unui proces este cuprinsă între cuvintele cheie process şi end process. Unui proces i se
poate asigna în mod opŃional un nume pentru identificarea mai uşoară a procesului în textul sursă. Numele este
un identificator şi trebuie urmat de caracterul ':' (cu rol de etichetă). Acest nume este util şi pentru simulare, de
exemplu, pentru setarea unui punct de întrerupere a execuŃiei simulării. Numele poate fi repetat la sfârşitul
declaraŃiei, după cuvintele cheie end process.
Lista de sensibilitate (opŃională) este lista semnalelor la a căror modificare procesul este “sensibil”.
Producerea unui eveniment asupra unuia din semnalele specificate în lista de sensibilitate va determina execuŃia
instrucŃiunilor secvenŃiale din cadrul procesului, similar cu instrucŃiunile dintr-un program obişnuit. Spre
deosebire de un limbaj de programare, în limbajul VHDL clauza end process nu specifică terminarea execuŃiei
procesului. Procesul va fi executat într-un ciclu infinit, iar în cazul în care se specifică o listă de sensibilitate,
procesul va fi doar suspendat după execuŃia ultimei instrucŃiuni, până la producerea unui nou eveniment asupra
semnalelor din listă. Se menŃionează că un eveniment are loc numai la modificarea valorii unui semnal. Astfel,
asignarea aceleiaşi valori la un semnal nu reprezintă un eveniment.
În cazul în care lista de sensibilitate lipseşte, procesul va fi executat în mod continuu. În acest caz,
procesul trebuie să conŃină o instrucŃiune wait pentru a determina suspendarea procesului şi activarea acestuia la
apariŃia unui eveniment sau îndeplinirea unei condiŃii. În cazul în care lista de sensibilitate este prezentă,
procesul nu poate conŃine instrucŃiuni wait. InstrucŃiunea wait este prezentată în secŃiunea 6.1.1.3.
Partea declarativă a procesului este cuprinsă între cuvintele cheie process şi begin. În această parte se
pot declara tipuri, constante, variabile şi subprograme (proceduri şi funcŃii) care sunt locale procesului.
Elementele declarate se pot utiliza deci numai în interiorul procesului.

ObservaŃie
• În cadrul unui proces nu pot fi declarate semnale, ci numai constante şi variabile.

Partea de instrucŃiuni a procesului începe după cuvântul cheie begin. Această parte conŃine
instrucŃiunile care vor fi executate la fiecare activare a procesului. Nu este permisă utilizarea instrucŃiunilor
concurente în interiorul unui proces.
În Exemplul 6.1 se prezintă declaraŃia unui proces simplu format dintr-o singură instrucŃiune de
asignare secvenŃială.

Exemplul 6.1
proc1: process (a, b, c)
begin
x <= a and b and c;
end process proc1;

6.1.1.2. Procese cu liste de sensibilitate incomplete

Unele sisteme de sinteză nu verifică listele de sensibilitate ale proceselor. Aceste sisteme presupun că
toate semnalele din partea dreaptă a asignărilor secvenŃiale la semnale se află în lista de sensibilitate. Astfel,
aceste sisteme vor interpreta cele două procese din Exemplul 6.2 ca fiind identice.

Exemplul 6.2
proc1: process (a, b, c)
begin
x <= a and b and c;
end process proc1;

proc2: process (a, b)


begin
x <= a and b and c;
end process proc2;

Toate sistemele de sinteză vor interpreta procesul proc1 ca o poartă ŞI cu 3 intrări. Unele sisteme de
sinteză vor interpreta procesul proc2 de asemenea ca o poartă ŞI cu 3 intrări, chiar dacă la simularea acestui cod
procesul nu se va comporta ca atare. La simulare, o modificare a valorii semnalului a sau b va determina
execuŃia procesului, iar valoarea funcŃiei ŞI logic între semnalele a, b şi c se va asigna semnalului x. Totuşi,
dacă se modifică valoarea semnalului c, procesul nu este executat, iar semnalul x nu este actualizat.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 3

Deoarece nu este clar modul în care un sistem de sinteză ar trebui să genereze un circuit pentru care o
tranziŃie a semnalului c nu determină o modificare a semnalului x, dar o modificare a semnalelor a sau b
determină actualizarea semnalului x cu valoarea funcŃiei ŞI logic între semnalele a, b şi c, există următoarele
alternative pentru sistemele de sinteză:
• Interpretarea procesului proc2 în mod identic cu procesul proc1 (cu o listă de sensibilitate care
cuprinde toate semnalele din partea dreaptă a instrucŃiunilor de asignare a semnalelor din cadrul
procesului);
• Indicarea unei erori la compilare, specificând faptul că nu se poate realiza sinteza procesului fără o listă
de sensibilitate completă.

A doua variantă este preferabilă, deoarece proiectantul va trebui să modifice codul sursă astfel încât
funcŃionarea circuitului generat să fie aceeaşi cu rezultatul simulării funcŃionale a codului sursă.
Deşi din punct de vedere sintactic procesele pot fi declarate fără o listă de sensibilitate şi fără o
instrucŃiune wait, asemenea procese nu vor fi suspendate niciodată. De aceea, dacă se va simula un asemenea
proces, timpul de simulare nu va avansa, deoarece faza de iniŃializare, în care toate procesele sunt executate până
când acestea sunt suspendate, nu se va termina niciodată (ciclul de simulare a fost descris în capitolul 5).

6.1.1.3. InstrucŃiunea wait

În locul unei liste de sensibilitate, un proces poate conŃine o instrucŃiune wait. Utilizarea unei
instrucŃiuni wait are două scopuri:
• Suspendarea execuŃiei unui proces;
• Specificarea condiŃiei care va determina activarea procesului suspendat.
La întâlnirea unei instrucŃiuni wait, procesul în care apare această instrucŃiune este suspendat. Atunci
când se îndeplineşte condiŃia specificată în cadrul instrucŃiunii wait, procesul este activat şi se execută
instrucŃiunile acestuia până când se întâlneşte din nou instrucŃiunea wait. Limbajul VHDL permite ca un proces
să conŃină mai multe instrucŃiuni wait. Atunci când se utilizează pentru modelarea logicii combinaŃionale în
vederea sintezei, un proces poate conŃine însă o singură instrucŃiune wait.
Dacă un proces conŃine o instrucŃiune wait, nu poate conŃine o listă de sensibilitate. Procesul din
Exemplul 6.3, care conŃine o instrucŃiune wait explicită, este echivalent cu procesul din Exemplul 6.1, care
conŃine o listă de sensibilitate. Ambele procese se vor executa atunci când apare o modificare a valorii
semnalelor a, b sau c.

Exemplul 6.3
proc3: process
begin
x <= a and b and c;
wait on a, b, c;
end process proc3;

Formele instrucŃiunii wait

Există trei forme ale instrucŃiunii wait:


wait on listă_de_sensibilitate;
wait until expresie_condiŃională;
wait for expresie_de_timp;

InstrucŃiunea wait on a fost ilustrată în exemplele precedente. InstrucŃiunea wait until suspendă un
proces până când condiŃia specificată devine adevărată datorită modificării unuia din semnalele care apar în
expresia condiŃională. Se menŃionează că dacă nici un semnal din această expresie nu se modifică, procesul nu va
fi activat, chiar dacă expresia condiŃională este adevărată. Exemplele următoare prezintă mai multe forme ale
instrucŃiunii wait until:
wait until semnal = valoare;
wait until semnal’event and semnal = valoare;
wait until not semnal’stable and semnal = valoare;
4 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

unde semnal este numele unui semnal, iar valoare este valoarea care se testează. Dacă semnalul este de tip
bit, atunci pentru valoarea '1' se aşteaptă frontul crescător al semnalului, iar pentru '0' frontul descrescător.
InstrucŃiunea wait until se poate utiliza pentru implementarea unei funcŃionări sincrone. În mod
obişnuit, semnalul testat este un semnal de ceas. De exemplu, aşteptarea frontului crescător al unui semnal de
ceas se poate exprima în următoarele moduri:
wait until clk = '1';
wait until clk'event and clk = '1';
wait until not clk'stable and clk = '1';

Pentru descrierile destinate sintezei, instrucŃiunea wait until trebuie să fie prima din cadrul
procesului. Din această cauză, logica sincronă descrisă cu o instrucŃiune wait until nu poate fi resetată în mod
asincron.
InstrucŃiunea wait for permite suspendarea execuŃiei unui proces pentru un timp specificat, de
exemplu:
wait for 10 ns;

Se pot combina mai multe condiŃii ale instrucŃiunii wait într-o condiŃie mixtă. În Exemplul 6.4,
procesul proc4 va fi activat la modificarea valorii unuia din semnalele a sau b, dar numai atunci când valoarea
semnalului clk este '1'.

Exemplul 6.4
proc4: process
begin
wait on a, b until clk = '1';
...
end process proc4;

PoziŃia instrucŃiunii wait

De obicei, instrucŃiunea wait apare fie la începutul unui proces, fie la sfârşitul acestuia. În Exemplul
6.3, instrucŃiunea wait apare la sfârşitul procesului. S-a menŃionat că această formă a procesului este echivalentă
cu forma care conŃine o listă de sensibilitate. Această echivalenŃă se datorează modului în care se execută
simularea unui model. În faza de iniŃializare a simulării, se execută toate procesele modelului. Dacă procesul
conŃine o listă de sensibilitate, toate instrucŃiunile procesului vor fi executate o singură dată. În forma procesului
care conŃine o instrucŃiune wait şi aceasta apare la sfârşit, în faza de iniŃializare se execută o singură dată toate
instrucŃiunile până la instrucŃiunea wait, ca şi în cazul formei care conŃine o listă de sensibilitate.
În cazul în care instrucŃiunea wait apare la începutul procesului, simularea se va executa în mod diferit,
deoarece în faza de iniŃializare procesul va fi suspendat fără a se executa nici o instrucŃiune a acestuia. Deci, un
proces cu instrucŃiunea wait plasată la început nu este echivalent cu un proces care conŃine o listă de
sensibilitate. Deoarece faza de iniŃializare a simulării nu are echivalent hardware, nu vor exista diferenŃe la
sinteza celor două procese cu instrucŃiunea wait plasată la sfârşit, respectiv la început.
Totuşi, din cauza diferenŃei între simulare şi sinteză în ceea ce priveşte faza de iniŃializare a simulării,
pot exista diferenŃe între funcŃionarea modelului la simulare şi funcŃionarea circuitului rezultat prin sinteză. Este
posibil ca modelul care funcŃionează corect la simulare să fie sintetizat într-un circuit a cărui funcŃionare este
eronată.

6.1.1.4. Procese combinaŃionale şi procese secvenŃiale

Atât procesele combinaŃionale, cât şi procesele secvenŃiale sunt interpretate în acelaşi fel, singura
deosebire dintre acestea fiind că la procesele secvenŃiale semnalele de ieşire se înscriu în bistabile. Un proces
combinaŃional simplu este prezentat în Exemplul 6.5.

Exemplul 6.5
proc5: process
begin
wait on a, b;
z <= a and b;
end process proc5;
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 5

Acest proces va fi implementat prin sinteză ca o simplă poartă ŞI cu două intrări.


Pentru ca un proces să modeleze un circuit combinaŃional, acesta trebuie să conŃină în lista de
sensibilitate toate semnalele care sunt intrări ale procesului. Cu alte cuvinte, procesul trebuie reevaluat de fiecare
dată când una din intrările circuitului pe care îl modelează se modifică. În acest fel se modelează în mod corect
un circuit combinaŃional.
Dacă un proces nu este sensibil la toate intrările sale şi nu este un proces secvenŃial, atunci nu poate fi
sintetizat, deoarece nu există un echivalent hardware al unui asemenea proces. Nu toate sistemele de sinteză
impun o asemenea regulă, astfel încât trebuie acordată atenŃie la scrierea proceselor combinaŃionale pentru a nu
introduce erori. Asemenea erori vor avea ca efect diferenŃe subtile între modelul simulat şi circuitul obŃinut prin
sinteză, deoarece un proces non-combinaŃional este interpretat de sistemul de sinteză ca un circuit combinaŃional.
Dacă un proces conŃine o instrucŃiune wait sau o instrucŃiune if semnal'event, procesul va fi
interpretat ca un proces secvenŃial. Astfel, procesul din Exemplul 6.6 va fi interpretat ca un proces secvenŃial.

Exemplul 6.6
proc6: process
begin
wait until clk = '1';
z <= a and b;
end process proc6;

Prin sinteza acestui proces, rezultă circuitul din Figura 6.1, unde s-a adăugat un bistabil la ieşire.

Figura 6.1. Rezultatul sintezei unui proces secvenŃial.

6.1.2. InstrucŃiunea secvenŃială de asignare a semnalelor


Semnalele reprezintă interfaŃa dintre domeniul concurent al unui model în limbajul VHDL şi domeniul
secvenŃial din cadrul unui proces. Un model VHDL este format dintr-un număr de procese care comunică între ele
prin intermediul semnalelor. La simulare, întreaga ierarhie din cadrul modelului este eliminată, rămânând numai
procesele şi semnalele. Simulatorul execută în mod alternativ actualizarea valorii unor semnale şi rularea
proceselor activate de modificarea valorii semnalelor aflate în listele lor de sensibilitate.

6.1.2.1. ExecuŃia instrucŃiunii secvenŃiale de asignare

Asignarea valorilor la semnale a fost prezentată pe scurt în capitolul 5. Această asignare se poate realiza
printr-o instrucŃiune secvenŃială sau o instrucŃiune concurentă. InstrucŃiunea secvenŃială poate apare doar în
interiorul unui proces, iar cea concurentă poate apare doar în exteriorul proceselor. InstrucŃiunea secvenŃială de
asignare are o singură formă, cea simplă, care este o asignare necondiŃionată. InstrucŃiunea concurentă are, pe
lângă forma sa simplă (prezentată în secŃiunea 6.2.3.1), încă două forme: asignarea condiŃională (secŃiunea
6.2.3.2) şi asignarea selectivă (secŃiunea 6.2.3.3). InstrucŃiunea secvenŃială de asignare are aceeaşi sintaxă cu
forma simplă a instrucŃiunii concurente de asignare, deosebirea dintre acestea rezultând din context.
InstrucŃiunea secvenŃială de asignare a unui semnal are sintaxa următoare:
semnal <= expresie [after întârziere];
Ca rezultat al execuŃiei acestei instrucŃiuni într-un proces, se evaluează expresia din dreapta simbolului
de asignare şi se planifică un eveniment care constă din modificarea valorii semnalului. Simulatorul va modifica
însă valoarea semnalului doar în momentul în care procesul va fi suspendat, iar în cazul în care se utilizează
clauza after, după întârzierea specificată din acest moment. Deci, într-un proces semnalele vor fi actualizate
doar după execuŃia tuturor instrucŃiunilor din cadrul procesului sau la întâlnirea unei instrucŃiuni wait.
În mod tipic, sistemele de sinteză nu permit utilizarea clauzelor after, sau ignoră aceste clauze.
Clauzele after sunt ignorate nu numai deoarece interpretarea lor pentru sinteză nu este specificată de standarde,
ci şi pentru că ar fi dificilă garantarea rezultatelor unor asemenea întârzieri. De exemplu, nu este clar dacă
6 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

întârzierea ar trebui interpretată ca o întârziere de propagare minimă sau maximă. De asemenea, nu este clar cum
trebuie să procedeze programul de sinteză dacă o întârziere specificată în codul sursă nu poate fi asigurată.
O consecinŃă a modului în care se execută asignarea semnalelor în cadrul proceselor este că în cazul în
care există mai multe asignări a unor valori diferite la acelaşi semnal, va avea efect doar ultima asignare. Astfel,
cele două procese din Exemplul 6.7 sunt echivalente.

Exemplul 6.7
proc7: process (a)
begin
z <= '0';
z <= a;
end process proc7;

proc8: process (a)


begin
z <= a;
end process proc8;

În concluzie, trebuie să se Ńină cont de următoarele aspecte importante la utilizarea instrucŃiunilor de


asignare a semnalelor în interiorul proceselor:
• Orice asignare a unei valori la un semnal devine efectivă numai atunci când procesul este suspendat.
Până în acel moment, toate semnalele îşi păstrează vechea valoare.
• Numai ultima asignare a unei valori la un semnal va fi executată efectiv. Deci, nu are sens să se
asigneze mai mult de o valoare la un semnal în acelaşi proces.

6.1.2.2. ReacŃii inverse

O altă consecinŃă a modului în care se execută asignarea semnalelor este că prin citirea unui semnal
căruia i se asignează o valoare în acelaşi proces se va obŃine valoarea care i-a fost asignată semnalului la execuŃia
precedentă a procesului. Citirea unui semnal şi asignarea unei valori la acel semnal în acelaşi proces este
echivalentă cu o reacŃie inversă. Într-un proces combinaŃional, valoarea precedentă este o ieşire a logicii
combinaŃionale, astfel încât reacŃia este asincronă. Într-un proces secvenŃial, valoarea precedentă este valoarea
memorată într-un bistabil sau registru, astfel încât reacŃia este sincronă.
În Exemplul 6.8 se prezintă un proces în care se utilizează reacŃia inversă sincronă. Procesul descrie un
numărător de 4 biŃi, semnalul num fiind de tip unsigned, tip care este declarat în pachetul numeric_bit. Se
observă că semnalul num este declarat în afara procesului.

Exemplul 6.8
library ieee;
use ieee.numeric_bit.all;

signal num: unsigned (3 downto 0);


process
begin
wait until clk = '1';
if reset = '1' then
num <= "0000";
else
num <= num + "0001";
end if;
end process;

Circuitul rezultat în urma sintezei procesului din exemplul anterior este prezentat în Figura 6.2.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 7

Figura 6.2. Exemplu de reacŃie inversă sincronă.

6.1.2.3. Întârzierea inerŃială

În limbajul VHDL există două tipuri de întârzieri care pot fi utilizate pentru modelarea sistemelor reale.
Acestea sunt întârzierea inerŃială şi întârzierea de transport. MenŃionăm că aceste întârzieri nu se pot utiliza
pentru sinteza logică.
Întârzierea inerŃială este implicită, fiind utilizată atunci când nu se specifică tipul întârzierii. Clauza
after presupune în mod automat întârzierea inerŃială. Într-un model cu întârziere inerŃială, două modificări
consecutive ale valorii unui semnal de intrare nu vor modifica valoarea unui semnal de ieşire dacă timpul dintre
aceste modificări este mai scurt decât întârzierea specificată. Această întârziere reprezintă inerŃia circuitului real.
Dacă, de exemplu, apar anumite impulsuri de durată scurtă ale semnalelor de intrare, semnalele de ieşire vor
rămâne neschimbate.

Figura 6.3. Ilustrarea întârzierii inerŃiale.

Figura 6.3 ilustrează întârzierea inerŃială cu ajutorul unui buffer simplu. Bufferul cu o întârziere de 20
ns are o intrare A şi o ieşire B. Semnalul A se modifică de la '0' la '1' la momentul 10 ns şi de la '1' la '0' la
momentul 20 ns. Impulsul semnalului de intrare are o durată de 10 ns, care este mai mică decât întârzierea
introdusă de buffer. Ca urmare, semnalul de ieşire B va rămâne la valoarea '0'.
Bufferul din Figura 6.3 poate fi modelat prin următoarea instrucŃiune de asignare:
b <= a after 20 ns;

6.1.2.4. Întârzierea de transport

Întârzierea de transport trebuie indicată în mod explicit prin cuvântul cheie transport. Aceasta
reprezintă întârzierea unei conexiuni, în care efectul apariŃiei unui impuls al unui semnal de intrare este propagat
la ieşire cu întârzierea specificată, indiferent de durata acestui impuls. Întârzierea de transport este utilă în special
pentru modelarea liniilor de transmisie şi a conexiunilor dintre componente.
Considerând acelaşi buffer din Figura 6.3 şi semnalul de intrare A cu aceeaşi formă, dacă se înlocuieşte
întârzierea inerŃială cu cea de transport se obŃine semnalul de ieşire B din Figura 6.4. Impulsul semnalului de
intrare este propagat nemodificat la ieşire cu o întârziere de 20 ns.
8 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Figura 6.4. Ilustrarea întârzierii de transport.

Dacă se utilizează întârzierea de transport, bufferul din Figura 6.4 poate fi modelat prin următoarea
instrucŃiune de asignare:
b <= transport a after 20 ns;

6.1.3. Variabile
RestricŃiile impuse asupra semnalelor reduc posibilităŃile de utilizare ale acestora. Deoarece semnalele
pot păstra numai ultima valoare asignată, ele nu pot fi utilizate pentru memorarea rezultatelor intermediare sau
temporare în cadrul unui proces. Un alt inconvenient este că noile valori sunt asignate semnalelor nu în
momentul execuŃiei instrucŃiunii de asignare, ci după suspendarea execuŃiei procesului. Aceasta determină ca
analiza unei descrieri să fie dificilă.
Spre deosebire de semnale, variabilele pot fi declarate în interiorul unui proces şi se pot utiliza pentru
memorarea rezultatelor intermediare. Variabilele pot fi utilizate însă numai în domeniul secvenŃial al limbajului
VHDL, deci în interiorul proceselor sau subprogramelor, şi nu pot fi declarate sau utilizate direct într-o
arhitectură. Ele sunt deci locale procesului sau subprogramului respectiv.

6.1.3.1. Declararea şi iniŃializarea variabilelor

Ca şi semnalele, variabilele trebuie declarate înainte de a fi utilizate. DeclaraŃia unei variabile este
similară cu cea a unui semnal, cu deosebirea că se utilizează cuvântul cheie variable. Această declaraŃie
specifică tipul variabilei. În mod opŃional, în cazul variabilelor scalare se poate specifica un domeniu restrâns, iar
în cazul variabilelor de tip tablou se poate specifica un index restrâns. Pentru ambele tipuri de variabile, se poate
specifica o valoare iniŃială. Exemplul 6.9 ilustrează declararea şi iniŃializarea variabilelor.

Exemplul 6.9
variable a, b, c: bit;
variable x, y: integer;
variable index range 1 to 10 := 1;
variable t_ciclu: time range 10 ns to 50 ns := 10 ns;
variable mem: bit_vector (0 to 15);

Unei variabile i se atribuie o valoare iniŃială în faza de iniŃializare a simulării. Această valoare iniŃială
este fie cea specificată în mod explicit la declararea variabilei, fie o valoare implicită, care este valoarea cea mai
din stânga a tipului. De exemplu, pentru tipul bit valoarea iniŃială implicită este '0', iar pentru tipul integer
această valoare este -2.147.483.647.
Pentru sinteză, nu există o interpretare hardware a valorilor iniŃiale, astfel încât sistemele de sinteză
ignoră valorile iniŃiale sau semnalează eroare.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 9

6.1.3.2. InstrucŃiunea de asignare a variabilelor

O instrucŃiune de asignare a unei variabile înlocuieşte valoarea curentă a variabilei cu o nouă valoare
specificată de o expresie. Expresia poate conŃine variabile, semnale şi literale. Variabila şi rezultatul evaluării
expresiei trebuie să fie de acelaşi tip. InstrucŃiunea de asignare a unei variabile are sintaxa următoare:
variabilă := expresie;
Această instrucŃiune este similară cu asignările din majoritatea limbajelor de programare. Spre
deosebire de o instrucŃiune secvenŃială de asignare a semnalelor, asignarea unei variabile este executată
instantaneu, deci într-un timp de simulare zero.
Există următoarele diferenŃe principale între asignarea semnalelor şi a variabilelor:
• În cazul asignării semnalelor, se planifică un eveniment pentru actualizarea valorii acestora, iar
actualizarea se execută numai la suspendarea procesului, în timp ce pentru asignarea variabilelor nu se
planifică un eveniment, iar actualizarea se execută instantaneu.
• La asignarea semnalelor se poate specifica o întârziere, în timp ce asignarea variabilelor nu poate fi
întârziată.
• Într-un proces, doar ultima asignare a unei valori la un semnal este efectivă. În schimb, pot exista
numeroase asignări la o variabilă în acelaşi proces, toate fiind efective.

Exemplul 6.10 ilustrează utilizarea variabilelor pentru memorarea rezultatelor intermediare.

Exemplul 6.10
entity add_1 is
port (a, b, cin: in bit;
s, cout: out bit);
end add_1;

architecture functional of add_1 is


begin
process (a, b, cin)
variable s1, s2, c1, c2: bit;
begin
s1 := a xor b;
c1 := a and b;
s2 := s1 xor cin;
c2 := s1 and cin;
s <= s2;
cout <= c1 or c2;
end process;
end functional;

Exemplul anterior descrie un sumator elementar. Acesta nu este modul optim de a descrie un sumator
elementar, dar ilustrează utilizarea variabilelor. Rezultatul se generează prin crearea a două semisumatoare,
primul generând ieşirile s1 şi c1, iar al doilea generând ieşirile s2 şi c2. În final, ieşirile sunt asignate celor două
porturi de ieşire s şi cout prin instrucŃiuni de asignare a semnalelor, deoarece porturile sunt semnale.

6.1.4. InstrucŃiunea if

6.1.4.1. Sintaxa şi execuŃia instrucŃiunii if

InstrucŃiunea if selectează pentru execuŃie una sau mai multe secvenŃe de instrucŃiuni, în funcŃie de
valoarea unei condiŃii corespunzătoare secvenŃei respective. Sintaxa acestei instrucŃiuni este următoarea:
if condiŃie then secvenŃă_de_instrucŃiuni
[elsif condiŃie then secvenŃă_de_instrucŃiuni ...]
[else secvenŃă_de_instrucŃiuni]
end if;
10 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Fiecare condiŃie este o expresie booleană, care se evaluează la valoarea TRUE sau FALSE. Pot exista mai
multe clauze elsif, dar poate exista o singură clauză else. Se evaluează mai întâi condiŃia de după cuvântul
cheie if, şi dacă este adevărată, se execută secvenŃa de instrucŃiuni corespunzătoare. În caz contrar, dacă este
prezentă clauza elsif, se evaluează condiŃia de după această clauză şi dacă această condiŃie este adevărată, se
execută secvenŃa de instrucŃiuni corespunzătoare. În caz contrar, dacă sunt prezente alte clauze elsif, se
continuă cu evaluarea condiŃiei acestor clauze. Dacă nici o condiŃie evaluată nu este adevărată, se execută
secvenŃa de instrucŃiuni corespunzătoare clauzei else, dacă aceasta este prezentă.

Exemplul 6.11
process (a, b)
begin
if a = b then
rez <= 0;
elsif a < b then
rez <= -1;
else
rez <= 1;
end if;
end process;

6.1.4.2. Interpretarea sintezei instrucŃiunii if

O instrucŃiune if poate fi implementată printr-un multiplexor. Considerăm mai întâi forma instrucŃiunii
if fără nici o ramură elsif. Exemplul 6.12 prezintă utilizarea unei asemenea instrucŃiuni pentru descrierea unui
comparator.

Exemplul 6.12
library ieee;
use ieee.numeric_bit.all;
entity comp is
port (a, b: in unsigned (7 downto 0);
egal: out bit);
end comp;

architecture functional of comp is


begin
process (a, b)
begin
if a = b then
egal <= '1';
else
egal <= '0';
end if;
end process;
end functional;

În exemplul anterior, se testează egalitatea a două semnale de tip unsigned, reprezentând două valori
întregi de câte 8 biŃi, rezultând o valoare de tip bit. Circuitul rezultat este prezentat în Figura 6.5. De notat că, la
fel ca şi în cazul altor exemple, în practică sistemul de sinteză va elimina ineficienŃele din circuit (în acest caz,
intrările constante la multiplexor) pentru a rezulta o soluŃie minimală.

Figura 6.5. Implementarea unei instrucŃiuni if.


Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 11

O instrucŃiune if cu ramuri multiple, în care apare cel puŃin o clauză elsif, este implementată prin
mai multe etaje de multiplexoare. Considerăm instrucŃiunea if din Exemplul 6.13.

Exemplul 6.13
process (a, b, c, s0, s1)
begin
if s0 = '1' then
z <= a;
elsif s1 = '1' then
z <= b;
else
z <= c;
end if;
end process;

Rezultatul implementării instrucŃiunii if din exemplul anterior este prezentat în Figura 6.6. Acest
circuit este echivalent cu cel rezultat prin implementarea unei instrucŃiuni de asignare condiŃională. Aceasta este
o instrucŃiune concurentă şi va fi prezentată în secŃiunea 6.2.3.2.

Figura 6.6. Implementarea unei instrucŃiuni if cu ramuri multiple.

CondiŃiile din ramurile succesive ale unei instrucŃiuni if sunt evaluate independent. În exemplul
anterior, condiŃiile implică cele două semnale s0 şi s1. Pot exista oricâte condiŃii, fiecare din acestea fiind
independentă de celelalte. Structura instrucŃiunii if asigură faptul că primele condiŃii vor fi testate înaintea
celorlalte. În acest exemplu, semnalul s0 a fost testat înaintea semnalului s1. Această prioritate se reflectă în
circuitul rezultat, în care multiplexorul controlat de semnalul s0 este mai apropiat de ieşire decât multiplexorul
controlat de semnalul s1.
Este important să se reŃină existenŃa acestei priorităŃi cu care se testează condiŃiile, astfel încât să fie
eliminate condiŃiile redundante. Considerăm instrucŃiunea if din Exemplul 6.14, care este echivalentă cu
instrucŃiunea if din Exemplul 6.13.

Exemplul 6.14
process (a, b, c, s0, s1)
begin
if s0 = '1' then
z <= a;
elsif s0 = '0' and s1 = '1' then
z <= b;
else
z <= c;
end if;
end process;

CondiŃia suplimentară s0 = '0' este redundantă, deoarece ea va fi testată numai dacă prima condiŃie a
instrucŃiunii if este falsă. Se recomandă evitarea unor asemenea redundanŃe, deoarece nu există garanŃia că ele
vor fi detectate şi eliminate de către sistemul de sinteză.
În cazul instrucŃiunilor if cu ramuri multiple, în mod normal fiecare condiŃie va fi dependentă de
semnale şi variabile diferite. Dacă fiecare ramură este dependentă de acelaşi semnal, atunci este mai avantajos să
se utilizeze o instrucŃiune case. InstrucŃiunea case este prezentată în secŃiunea 6.1.5.
12 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

6.1.4.3. InstrucŃiuni if incomplete

În exemplele prezentate până acum, toate instrucŃiunile if au fost complete. Cu alte cuvinte, semnalului
destinaŃie i s-a asignat o valoare în toate condiŃiile posibile. Sunt posibile însă două situaŃii în care unui semnal
nu i se asignează o valoare: atunci când lipseşte clauza else a instrucŃiunii if sau atunci când unui semnal nu i
se asignează o valoare într-o ramură a instrucŃiunii if. În ambele cazuri, interpretarea este aceeaşi. În situaŃiile în
care unui semnal nu i se asignează o valoare, semnalul îşi păstrează valoarea precedentă.
Se pune însă problema care este valoarea precedentă a semnalului. Dacă există o instrucŃiune anterioară
de asignare în care semnalul apare ca destinaŃie, valoarea precedentă provine de la acea instrucŃiune de asignare.
În caz contrar, valoarea provine din execuŃia precedentă a procesului, ceea ce conduce la existenŃa unei reacŃii
inverse în cadrul circuitului.
Primul caz este ilustrat prin Exemplul 6.15.

Exemplul 6.15
process (a, b, enable)
begin
z <= a;
if enable = '1' then
z <= b;
end if;
end process;

În acest caz, instrucŃiunea if este incompletă deoarece lipseşte clauza else. În instrucŃiunea if,
semnalul z primeşte o valoare în cazul în care condiŃia enable = '1' este adevărată, dar rămâne la valoarea
precedentă în cazul în care condiŃia este falsă. Valoarea precedentă provine din instrucŃiunea de asignare aflată
înaintea instrucŃiunii if.
InstrucŃiunea if din Exemplul 6.15 este echivalentă cu instrucŃiunea if din exemplul următor.

Exemplul 6.16
process (a, b, enable)
begin
if enable = '1' then
z <= b;
else
z <= a;
end if;
end process;

În cazul în care instrucŃiunea if este incompletă şi nu există o instrucŃiune anterioară de asignare, va


exista o reacŃie inversă de la ieşirea circuitului la intrare. Aceasta deoarece valoarea semnalului de la execuŃia
precedentă a procesului este păstrată şi aceasta devine valoarea semnalului la execuŃia curentă a procesului.
O asemenea formă a instrucŃiunii if este utilizată pentru a descrie un bistabil sau un registru cu o
intrare de validare, ca în Exemplul 6.17.

Exemplul 6.17
process
begin
wait until clk = '1';
if en = '1' then
q <= d;
end if;
end process;

Semnalul q este actualizat cu noua valoare a semnalului d în cazul în care condiŃia este adevărată, dar
nu este actualizat în cazul în care condiŃia este falsă. În acest caz, valoarea precedentă a semnalului q este
păstrată prin reacŃia inversă secvenŃială a semnalului q. Circuitul rezultat este prezentat în Figura 6.7.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 13

Figura 6.7. Implementarea unei instrucŃiuni if incomplete.

InstrucŃiunea if din Exemplul 6.17 este echivalentă cu instrucŃiunea if completă din exemplul
următor.

Exemplul 6.18
process
begin
wait until clk = '1';
if en = '1' then
q <= d;
else
q <= q;
end if;
end process;

În cazul în care condiŃia este falsă, se asignează semnalului q valoarea anterioară a acestuia, ceea ce este
echivalent cu păstrarea valorii sale anterioare.
Una din cele mai obişnuite erori întâlnite în descrierile VHDL destinate sintezei logice este introducerea
neintenŃionată a reacŃiei inverse în circuit datorită unei instrucŃiuni if incomplete. Pentru a evita introducerea
reacŃiei inverse, proiectantul trebuie să se asigure că fiecare semnal căruia i se asignează o valoare într-un proces
(care este deci un semnal de ieşire din proces) primeşte o valoare în fiecare combinaŃie posibilă a condiŃiilor. În
practică, există două posibilităŃi pentru aceasta: asignarea unei valori unui semnal de ieşire în fiecare ramură a
instrucŃiunii if şi includerea clauzei else, sau iniŃializarea semnalului printr-o instrucŃiune de asignare
necondiŃionată înaintea instrucŃiunii if.
În exemplul următor, deşi instrucŃiunea if pare completă, în cele două ramuri ale instrucŃiunii
asignările se efectuează la semnale diferite. De aceea, ambele semnale z şi y vor avea o reacŃie inversă
asincronă.

Exemplul 6.19
process
begin
wait on a, b, c;
if c = '1' then
z <= a;
else
y <= b;
end if;
end process;

Un alt exemplu este cel în care există un test redundant al unei condiŃii care trebuie să fie adevărată
(Exemplul 6.20).

Exemplul 6.20
process
begin
wait on a, b, c;
if c = '1' then
z <= a;
elsif c = '0' then
z <= b;
end if;
end process;
14 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

În acest caz, deşi instrucŃiunea if pare completă (presupunând că semnalul c este de tip bit), deoarece
pentru fiecare condiŃie testată sinteza se realizează în mod independent, sistemul de sinteză nu va detecta faptul
că a doua condiŃie este redundantă. De aceea, instrucŃiunea if va fi implementată printr-un multiplexor cu trei
căi, a treia intrare fiind condiŃia ramurii else care lipseşte, aceasta fiind reacŃia inversă a valorii anterioare.
Circuitul implementat pentru acest exemplu este prezentat în Figura 6.8.

Figura 6.8. Implementarea unei instrucŃiuni if cu o condiŃie redundantă.

6.1.4.4. InstrucŃiuni if în care apar variabile

Până acum, în instrucŃiunile if au fost utilizate doar semnale. Aceleaşi reguli se aplică şi în cazul
utilizării variabilelor, cu o singură diferenŃă. Ca şi în cazul unui semnal, dacă unei variabile i se asignează valori
numai în anumite ramuri ale instrucŃiunii if, se păstrează valoarea anterioară a variabilei prin reacŃie inversă.
Spre deosebire de cazul utilizării unui semnal, citirea şi scrierea unei variabile în acelaşi proces va determina o
reacŃie inversă numai dacă citirea apare înaintea scrierii. În acest caz, valoarea citită este valoarea precedentă a
variabilei. În cazul citirii şi scrierii în acelaşi proces a unui semnal, va rezulta întotdeauna o reacŃie inversă.
Această observaŃie se poate utiliza pentru a crea registre sau numărătoare utilizând variabile. Reamintim
că un proces secvenŃial este interpretat la sinteză prin plasarea unui bistabil sau registru înaintea ieşirii fiecărui
semnal căruia i s-a asignat o valoare în procesul respectiv. Aceasta înseamnă că în mod normal variabilele nu
sunt înscrise în bistabile sau registre. Dacă există însă o reacŃie inversă a valorii precedente a unei variabile,
această reacŃie se realizează printr-un bistabil sau registru pentru ca procesul să fie sincron.
În Exemplul 6.21 se descrie un numărător utilizând tipul întreg unsigned. La incrementarea unei
valori de tip unsigned, dacă valoarea este cea maximă a domeniului se obŃine valoarea minimă a domeniului.

Exemplul 6.21
process
variable num: unsigned (7 downto 0);
begin
wait until clk = '1';
if reset = '1' then
num := "00000000";
else
num := num + 1;
end if;
rez <= num;
end process;

În acest exemplu, în ramura else a instrucŃiunii if se citeşte valoarea precedentă a variabilei num
pentru a calcula valoarea următoare. Rezultă astfel o reacŃie inversă.
De notat că în acest exemplu se crează de fapt două registre. Conform regulilor pentru reacŃia inversă,
variabila num va fi înscrisă într-un registru. Semnalul rez va fi de asemenea înscris într-un registru, deoarece
toate semnalele cărora li se asignează o valoare într-un proces secvenŃial vor fi înscrise în registre. Acest registru
suplimentar va conŃine întotdeauna aceeaşi valoare ca şi registrul variabilei num. Sistemul de sinteză va elimina
în mod normal acest registru redundant.

6.1.5. InstrucŃiunea case

Ca şi instrucŃiunea if, instrucŃiunea case selectează pentru execuŃie una din mai multe secvenŃe
alternative de instrucŃiuni pe baza valorii unei expresii. Spre deosebire de instrucŃiunea if, în cazul instrucŃiunii
case expresia nu trebuie să fie booleană, ci poate fi reprezentată de un semnal, o variabilă sau o expresie de
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 15

orice tip discret (un tip enumerat sau întreg) sau un tablou unidimensional de caractere (inclusiv bit_vector
sau std_logic_vector). InstrucŃiunea case se utilizează atunci când există un număr mare de alternative
posibile. Această instrucŃiune este mai lizibilă decât o instrucŃiune if cu un număr mare de ramuri, permiŃând
identificarea uşoară a unei valori şi a secvenŃei de instrucŃiuni asociate.
Sintaxa instrucŃiunii case este următoarea:
case expresie is
when opŃiuni_1 =>
secvenŃă_de_instrucŃiuni
...
when opŃiuni_n =>
secvenŃă_de_instrucŃiuni
[when others =>
secvenŃă_de_instrucŃiuni]
end case;

InstrucŃiunea case conŃine mai multe clauze when, fiecare specificând una sau mai multe opŃiuni.
OpŃiunile reprezintă fie o valoare individuală, fie un set de valori cu care se compară expresia instrucŃiunii case.
În cazul în care expresia este egală cu valoarea individuală sau cu una din valorile setului, se execută secvenŃa de
instrucŃiuni specificată după simbolul =>. O secvenŃă de instrucŃiuni poate fi formată şi din instrucŃiunea nulă,
null. Spre deosebire de anumite limbaje de programare, instrucŃiunile dintr-o secvenŃă nu trebuie incluse între
cuvintele cheie begin şi end. Clauza others se poate utiliza pentru a specifica execuŃia unei secvenŃe de
instrucŃiuni în cazul în care valoarea expresiei nu este egală cu nici una din valorile specificate în clauzele when.
În cazul în care o opŃiune este reprezentată de un set de valori, se pot specifica fie valorile individuale
din set, separate prin simbolul “|” având semnificaŃia “sau”, fie domeniul valorilor, fie o combinaŃie a acestora,
după cum se arată în exemplul următor.
case expresie is
when val =>
secvenŃă_de_instrucŃiuni
when val1 | val2 | ... | valn =>
secvenŃă_de_instrucŃiuni
when val3 to val4 =>
secvenŃă_de_instrucŃiuni
when val5 to val6 | val7 to val8 =>
secvenŃă_de_instrucŃiuni
...
when others =>
secvenŃă_de_instrucŃiuni
end case;

ObservaŃii
• Într-o instrucŃiune case trebuie enumerate toate valorile posibile pe care le poate avea expresia de
selecŃie, Ńinând cont de tipul sau subtipul acesteia. De exemplu, dacă expresia de selecŃie este de tip
std_logic_vector de 2 biŃi, trebuie enumerate 81 de valori, deoarece pentru un singur bit pot exista
9 valori posibile. Dacă nu sunt enumerate toate valorile, trebuie utilizată clauza others.
• Clauza others trebuie să fie ultima dintre toate opŃiunile.

Exemplul 6.22 prezintă un proces pentru secvenŃierea valorilor unui tip enumerat reprezentând stările
unui semafor. Procesul este descris cu ajutorul unei instrucŃiuni case.

Exemplul 6.22
type tip_culoare is (rosu, galben, verde);
process (culoare)
case culoare is
when rosu =>
culoare_urm <= verde;
when galben =>
culoare_urm <= rosu;
when verde =>
culoare_urm <= galben;
end case;
end process;
16 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Exemplul 6.23 defineşte o entitate şi o arhitectură pentru o poartă SAU EXCLUSIV cu două intrări.
Poarta este descrisă în mod funcŃional cu ajutorul unui proces care conŃine o instrucŃiune case.

Exemplul 6.23
library ieee;
use ieee.std_logic_1164.all;
entity xor2 is
port (a, b: in std_logic;
x: out std_logic);
end xor2;

architecture arh_xor2 of xor2 is


begin
process (a, b)
variable temp: std_logic_vector (1 downto 0);
begin
temp := a & b;
case temp is
when "00" => x <= '0';
when "01" => x <= '1';
when "10" => x <= '1';
when "11" => x <= '0';
when others => x <= '0';
end case;
end process;
end arh_xor2;

O instrucŃiune case este implementată printr-un multiplexor, asemănător instrucŃiunii if. Deosebirea
este că toate opŃiunile depind de aceeaşi intrare şi sunt mutual exclusive. Aceasta permite anumite optimizări ale
condiŃiilor de control comparativ cu o instrucŃiune if cu ramuri multiple, la care nu se va presupune nici o
dependenŃă între diferitele condiŃii.

6.1.6. InstrucŃiuni de buclare


InstrucŃiunile de buclare permit execuŃia repetată a unei secvenŃe de instrucŃiuni, de exemplu,
prelucrarea fiecărui element al unui tablou în acelaşi mod. În limbajul VHDL, există trei tipuri de instrucŃiuni de
buclare: instrucŃiunea de buclare simplă loop, instrucŃiunea while loop şi instrucŃiunea for loop.
InstrucŃiunea de buclare simplă loop specifică repetarea unor instrucŃiuni în mod nedefinit. În cazul instrucŃiunii
while loop, instrucŃiunile care formează corpul buclei sunt repetate cât timp condiŃia specificată este
adevărată, iar în cazul instrucŃiunii for loop instrucŃiunile din corpul buclei sunt repetate de un număr de ori
specificat de un contor.

ObservaŃie
• Singura instrucŃiune de buclare care poate fi utilizată pentru sinteza logică este instrucŃiunea for loop,
deoarece la aceasta numărul de iteraŃii este fix.

6.1.6.1. InstrucŃiunea loop

InstrucŃiunea de buclare simplă loop are sintaxa următoare:


[etichetă:] loop
secvenŃă_de_instrucŃiuni
end loop [etichetă];
InstrucŃiunea are o etichetă opŃională, care poate fi utilizată pentru identificarea instrucŃiunii.
InstrucŃiunea loop are ca efect repetarea instrucŃiunilor din corpul buclei de un număr nelimitat de ori. În cazul
acestei instrucŃiuni, singura posibilitate de terminare a execuŃiei este utilizarea unei instrucŃiuni exit (prezentată
în secŃiunea 6.1.6.5).
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 17

6.1.6.2. InstrucŃiunea while loop

InstrucŃiunea while loop este o instrucŃiune de buclare condiŃionată. Sintaxa acestei instrucŃiuni este
următoarea:
[etichetă:] while condiŃie loop
secvenŃă_de_instrucŃiuni
end loop [etichetă];
CondiŃia este testată înaintea fiecărei execuŃii a buclei. Dacă această condiŃie este adevărată, se execută
secvenŃa de instrucŃiuni din corpul buclei, după care controlul este transferat la începutul buclei. ExecuŃia buclei
se termină atunci când condiŃia testată devine falsă, caz în care se execută instrucŃiunea care urmează după
clauza end loop.

Exemplul 6.24
process
variable contor: integer := 0;
begin
wait until clk = '1';
while nivel = '1' loop
contor := contor + 1;
wait until clk = '0';
end loop;
end process;

În procesul din Exemplul 6.24 se numără fronturile crescătoare ale semnalului de ceas clk atât timp cât
semnalul nivel are valoarea '1'. Stabilitatea semnalului nivel nu este testată. Se testează doar dacă acest
semnal are valoarea '1' la detectarea unui front crescător al semnalului clk, şi nu se testează dacă valoarea
semnalului nivel s-a modificat de la testarea anterioară.
InstrucŃiunile de buclare pot fi imbricate pe mai multe nivele. Deci, corpul buclei unei instrucŃiuni
while loop poate conŃine o altă instrucŃiune de buclare, în particular o instrucŃiune while loop, după cum se
arată în exemplul următor.
E1: while i < 10 loop
E2: while j < 20 loop
...
end loop E2;
end loop E1;

6.1.6.3. InstrucŃiunea for loop

Pentru execuŃia repetată a unei secvenŃe de instrucŃiuni de un număr de ori specificat se poate utiliza
instrucŃiunea for loop. Sintaxa acestei instrucŃiuni este următoarea:
[etichetă:] for contor in domeniu loop
secvenŃă_de_instrucŃiuni
end loop [etichetă];

Într-o instrucŃiune for loop se specifică un contor de iteraŃii şi un domeniu. InstrucŃiunile din corpul
buclei sunt executate cât timp contorul se află în domeniul specificat. După terminarea unei iteraŃii, contorului i
se asignează următoarea valoare din domeniu. Domeniul poate fi unul crescător, specificat prin cuvântul cheie
to, sau descrescător, specificat prin cuvântul cheie downto. Acest domeniu poate fi specificat şi sub forma unui
tip enumerat sau subtip, caz în care nu se specifică în mod explicit limitele domeniului în cadrul instrucŃiunii
for loop. Limitele domeniului vor fi determinate de compilator din declaraŃia tipului sau subtipului respectiv.
InstrucŃiunea for loop din Exemplul 6.25 calculează pătratele valorilor întregi cuprinse între 1 şi 10,
pe care le depune în tabloul i_patrat.

Exemplul 6.25
for i in 1 to 10 loop
i_patrat (i) <= i * i;
end loop;
18 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Contorul de iteraŃii din acest exemplu este în mod implicit de tip integer, deoarece tipul acestuia nu a
fost definit în mod explicit. Forma completă a declaraŃiei domeniului pentru contorul de iteraŃii este similară cu
cea a unui tip. Pentru exemplul anterior, clauza for poate fi scrisă şi sub forma următoare:
for i in integer range 1 to 10 loop
În unele limbaje de programare, în cadrul buclei se poate asigna o valoare contorului de iteraŃii (în
exemplul anterior, i) pentru a-i modifica valoarea. Limbajul VHDL nu permite însă asignarea unei valori
contorului de iteraŃii sau utilizarea acestuia ca parametru de intrare sau de ieşire al unei proceduri. Contorul
poate fi utilizat însă într-o expresie, cu condiŃia să nu i se modifice valoarea. Un alt aspect legat de contorul de
iteraŃii este că acesta nu trebuie declarat în mod explicit în cadrul procesului. Acest contor este declarat în mod
implicit ca o variabilă locală a instrucŃiunii de buclare prin specificarea sa după cuvântul cheie for. Dacă există
o altă variabilă cu acelaşi nume în cadrul procesului, cele două vor fi tratate ca variabile separate.
Interpretarea sintezei instrucŃiunii for loop este aceea că se realizează o nouă copie a circuitului
descris de conŃinutul instrucŃiunii la fiecare iteraŃie a buclei. Utilizarea instrucŃiunii for loop pentru generarea
unui circuit este ilustrată în Exemplul 6.26.

Exemplul 6.26
entity potrivire_biti is
port (a, b: in bit_vector (7 downto 0);
potriviri: out bit_vector (7 downto 0));
end potrivire_biti;

architecture functional of potrivire_biti is


begin
process (a, b)
begin
for i in 7 downto 0 loop
potriviri (i) <= not (a(i) xor b(i));
end loop;
end process;
end functional;

Prin procesul din acest exemplu, se generează un set de comparatoare de câte un bit, care compară biŃii
de acelaşi rang ai vectorilor a şi b. Rezultatul este înscris în vectorul potriviri, care va conŃine '1' în poziŃiile
în care biŃii celor doi vectori sunt identici şi '0' în celelalte poziŃii.
Procesul din exemplul anterior este echivalent cu următorul proces:
process (a, b)
begin
potriviri (7) <= not (a(7) xor b(7));
potriviri (6) <= not (a(6) xor b(6));
potriviri (5) <= not (a(5) xor b(5));
potriviri (4) <= not (a(4) xor b(4));
potriviri (3) <= not (a(3) xor b(3));
potriviri (2) <= not (a(2) xor b(2));
potriviri (1) <= not (a(1) xor b(1));
potriviri (0) <= not (a(0) xor b(0));
end process;

În acest caz, ordonarea domeniului contorului de iteraŃii nu are importanŃă, deoarece nu există
conexiune între blocurile generate ale circuitului. Această ordonare devine importantă atunci când există o
conexiune între aceste blocuri. Această conexiune este creată de obicei de către o variabilă care păstrează o
valoare într-o iteraŃie a buclei, valoare care este citită apoi într-o altă iteraŃie. De obicei, este necesară
iniŃializarea unei asemenea variabile înaintea intrării în buclă. Exemplul 6.27 prezintă un asemenea circuit.

Exemplul 6.27
library ieee;
use ieee.numeric_bit.all;
entity contorizare_unu is
port (v: in bit_vector (15 downto 0);
num: out signed (3 downto 0));
end contorizare_unu;
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 19

architecture functional of contorizare_unu is


begin
process (v)
variable rez: signed (3 downto 0);
begin
rez := (others => '0');
for i in 15 downto 0 loop
if v(i) = '1' then
rez := rez + 1;
end if;
end loop;
num <= rez;
end process;
end functional;

Acest exemplu este un circuit combinaŃional care contorizează numărul biŃilor din vectorul v care sunt
'1'. Rezultatul este acumulat pe parcursul execuŃiei procesului într-o variabilă numită rez şi este asignată apoi
semnalului de ieşire num la sfârşitul procesului. Corpul buclei – o instrucŃiune if conŃinând o asignare a unei
variabile – reprezintă un bloc format dintr-un multiplexor şi un sumator, care va fi generat la sinteză pentru
fiecare iteraŃie a buclei. Ieşirea unui bloc devine intrarea rez a următorului bloc. Figura 6.9 prezintă circuitul
generat.

Figura 6.9. Implementarea unei instrucŃiuni for loop.

În Exemplul 6.27, domeniul contorului de iteraŃii al instrucŃiunii for loop a fost specificat în mod
explicit ca fiind 15 downto 0. În practică, această specificare explicită este utilizată foarte rar pentru accesarea
tablourilor, fiind recomandată utilizarea atributelor pentru tablouri. Există patru posibilităŃi, în funcŃie de
domeniul crescător sau descrescător al tabloului sau de ordinea în care trebuie parcurse elementele tabloului.
1. Dacă elementele unui tablou trebuie parcurse de la stânga la dreapta, indiferent de domeniul crescător
sau descrescător al tabloului, se utilizează atributul 'range:
for i in v'range loop
2. Dacă elementele unui tablou trebuie parcurse de la dreapta la stânga, se utilizează atributul
'reverse_range:
for i in v'reverse_range loop
3. Dacă elementele unui tablou trebuie parcurse de la indexul minim la cel maxim, indiferent de domeniul
crescător sau descrescător al tabloului, se utilizează atributele 'low şi 'high:
for i in v'low to v'high loop
4. În sfârşit, dacă elementele unui tablou trebuie parcurse de la indexul maxim la cel minim, se utilizează
atributele 'high şi 'low, cu specificarea cuvântului cheie downto:
for i in v'high downto v'low loop
La scrierea subprogramelor, în cazul în care nu se cunoaşte dinainte dacă o variabilă sau un semnal de
tip tablou va avea un domeniu crescător sau descrescător, devine foarte importantă alegerea limitelor corecte
pentru instrucŃiunile de buclare. Această problemă va fi prezentată mai detaliat în capitolul 9. Pentru tipurile
tablou care reprezintă valori întregi, cum sunt tipurile signed şi unsigned definite în pachetele numeric_bit
şi numeric_std, convenŃia este că bitul din stânga reprezintă bitul c.m.s. şi bitul din dreapta reprezintă bitul
c.m.p.s., indiferent de domeniul tabloului. Aceasta înseamnă că modul corect pentru accesul acestor tablouri este
utilizarea atributului 'range sau 'reverse_range.
20 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Astfel, pentru accesul unui tablou n reprezentând o valoare întreagă începând de la bitul c.m.s. spre
bitul c.m.p.s., se va utiliza atributul 'range:
for i in n'range loop
Pentru accesul aceluiaşi tablou începând de la bitul c.m.p.s. spre bitul c.m.s., se va utiliza atributul
'reverse_range:
for i in n'reverse_range loop

Din cauza interpretării sintezei instrucŃiunii for loop, limitele domeniului buclei trebuie să fie
constante. Aceasta înseamnă că limitele nu pot fi definite utilizând valoarea unei variabile sau semnal. Această
restricŃie determină ca descrierea unor circuite să fie dificilă. De exemplu, considerăm cazul în care trebuie
contorizat numărul de zerouri de la începutul unei valori întregi, şi deci numărul de iteraŃii necesar nu este
cunoscut dinainte. Descrierea unor asemenea circuite cu ajutorul instrucŃiunilor de buclare este facilitată prin
utilizarea instrucŃiunilor next şi exit.

6.1.6.4. InstrucŃiunea next

Există situaŃii în care este necesară oprirea execuŃiei instrucŃiunilor dintr-o buclă în iteraŃia curentă şi
trecerea la următoarea iteraŃie. Pentru aceasta se poate utiliza instrucŃiunea next. Sintaxa acestei instrucŃiuni este
următoarea:
next [etichetă] [when condiŃie];

La întâlnirea unei instrucŃiuni next în cadrul corpului unei bucle, execuŃia iteraŃiei curente este oprită şi
controlul este transferat la începutul instrucŃiunii de buclare, fie necondiŃionat, dacă clauza when nu este
prezentă, fie condiŃionat, dacă această clauză este prezentă. Contorul de iteraŃii va fi actualizat, iar dacă limita
domeniului nu a fost atinsă, execuŃia va continua cu prima instrucŃiune din corpul buclei. În caz contrar, execuŃia
instrucŃiunii de buclare se va termina.
În cazul în care există mai multe nivele de instrucŃiuni de buclare (o buclă conŃinută într-o altă buclă), în
cadrul instrucŃiunii next se poate specifica o etichetă, aceasta fiind eticheta instrucŃiunii de buclare de nivel
imediat superior în care este cuprinsă instrucŃiunea next. Această etichetă are doar rolul de a creşte claritatea
descrierii şi nu poate fi diferită de cea a instrucŃiunii de buclare curente.
O instrucŃiune next se poate utiliza în locul unei instrucŃiuni if pentru execuŃia condiŃionată a unui
grup de instrucŃiuni. Pentru sinteza instrucŃiunii next sunt necesare aceleaşi circuite ca şi cele necesare pentru
sinteza instrucŃiunii if. Alegerea uneia din cele două instrucŃiuni rămâne la latitudinea proiectantului.
Ca un exemplu, considerăm acelaşi circuit care contorizează numărul biŃilor de '1' dintr-un vector.
Exemplul 6.28 prezintă descrierea modificată a acestui circuit. În locul instrucŃiunii if se utilizează o
instrucŃiune next, prin care se abandonează o iteraŃie în cazul în care valoarea elementului curent este '0', astfel
că nu se execută incrementarea contorului.

Exemplul 6.28
library ieee;
use ieee.numeric_bit.all;
entity contorizare_unu is
port (v: in bit_vector (15 downto 0);
num: out signed (3 downto 0));
end contorizare_unu;

architecture functional of contorizare_unu is


begin
process (v)
variable rez: signed (3 downto 0);
begin
rez := (others => '0');
for i in v'range loop
next when v(i) = '0';
rez := rez + 1;
end loop;
num <= rez;
end process;
end functional;
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 21

Figura 6.10. Implementarea unei instrucŃiuni for loop care conŃine o instrucŃiune next.

Figura 6.10 prezintă circuitul generat prin sinteza descrierii din exemplul anterior. Singura diferenŃă
dintre acest circuit şi cel din Figura 6.9 este că este inversată logica de control a multiplexoarelor. Cele două
circuite sunt însă echivalente funcŃional.

6.1.6.5. InstrucŃiunea exit

Există situaŃii în care execuŃia unei instrucŃiuni de buclare trebuie oprită complet, fie datorită apariŃiei
unei erori în timpul execuŃiei unui model, fie datorită faptului că prelucrarea trebuie terminată înaintea depăşirii
domeniului de către contorul de iteraŃii. În asemenea situaŃii, se poate utiliza instrucŃiunea exit. Sintaxa acestei
instrucŃiuni este următoarea:
exit [etichetă] [when condiŃie];

Există trei forme ale instrucŃiunii exit. Prima este cea în care nu apare o etichetă şi nici o condiŃie
specificată printr-o clauză when. În acest caz, se va opri în mod necondiŃionat execuŃia instrucŃiunii curente de
buclare. În cazul în care instrucŃiunea exit apare într-o instrucŃiune de buclare aflată în interiorul unei alte
instrucŃiuni de buclare, va fi oprită doar execuŃia instrucŃiunii interioare de buclare, dar execuŃia instrucŃiunii
exterioare de buclare va continua.
Dacă în instrucŃiunea exit se specifică o etichetă a unei instrucŃiuni de buclare, la întâlnirea
instrucŃiunii exit controlul va fi transferat la eticheta specificată.
Dacă instrucŃiunea exit conŃine o clauză when, execuŃia instrucŃiunii de buclare va fi oprită numai în
cazul în care condiŃia specificată de această clauză este adevărată. Următoarea instrucŃiune executată depinde de
prezenŃa sau absenŃa unei etichete în cadrul instrucŃiunii. Dacă se specifică o etichetă a unei instrucŃiuni de
buclare, următoarea instrucŃiune executată va fi prima din instrucŃiunea de buclare specificată de acea etichetă.
Dacă nu se specifică o etichetă, următoarea instrucŃiune executată va fi cea de după clauza end loop a
instrucŃiunii de buclare curente.
InstrucŃiunea exit se poate utiliza pentru a termina execuŃia unei instrucŃiuni loop simple, după cum
se arată în Exemplul 6.30.

Exemplul 6.30
E3: loop
a := a + 1;
exit E3 when a > 10;
end loop E3;

Exemplul 6.31 prezintă descrierea unui circuit pentru contorizarea numărului de zerouri de la sfârşitul
unui vector de biŃi. Se testează fiecare element al vectorului reprezentând o valoare întreagă, iar dacă un element
este '1', bucla se termină cu ajutorul instrucŃiunii exit.

Exemplul 6.31
library ieee;
use ieee.numeric_bit.all;
entity contorizare_zero is
port (v: in bit_vector (15 downto 0);
num: out signed (3 downto 0));
end contorizare_zero;

architecture functional of contorizare_zero is


begin
22 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

process (v)
variable rez: signed (3 downto 0);
begin
rez := (others => '0');
for i in v'reverse_range loop
exit when v(i) = '1';
rez := rez + 1;
end loop;
num <= rez;
end process;
end functional;

Figura 6.11. Implementarea unei instrucŃiuni for loop care conŃine o instrucŃiune exit.

Circuitul generat prin sinteza descrierii din exemplul anterior este prezentat în Figura 6.11.
InstrucŃiunea exit este implementată prin porŃile SAU care determină, pentru iteraŃia curentă şi toate iteraŃiile
rămase, selectarea intrării multiplexoarelor care nu conŃin circuitul de incrementare atunci când condiŃia
instrucŃiunii exit devine adevărată. Se poate observa că implementarea unei instrucŃiuni exit dintr-o buclă este
similară cu cea a unei instrucŃiuni if dintr-o buclă.

6.1.7. InstrucŃiunea secvenŃială assert

InstrucŃiunea assert este utilă pentru afişarea unor mesaje de avertisment sau de eroare în timpul
simulării unui model. Această instrucŃiune testează valoarea unei condiŃii booleene şi afişează mesajul specificat
în cazul în care condiŃia este falsă. Sintaxa instrucŃiunii este următoarea:
assert condiŃie
[report şir_de_caractere]
[severity nivel_de_severitate];
CondiŃia specificată este o expresie care trebuie să se evalueze la o valoare booleană. Dacă această
valoare este TRUE, instrucŃiunea nu are nici un efect. Dacă valoarea este FALSE, se afişează textul specificat în
clauza report.
Clauza opŃională report poate avea ca argument un şir de caractere, cu tipul predefinit string. Dacă
această clauză nu este specificată, şirul de caractere care va fi afişat în mod implicit va fi "Assertion
violation".
Clauza opŃională severity permite specificarea nivelului de severitate al violării aserŃiunii. Nivelul de
severitate trebuie să fie o expresie cu tipul predefinit severity_level. Acest tip conŃine următoarele valori, în
ordinea crescătoare a nivelului de severitate: note, warning, error şi failure. Dacă această clauză este
omisă, se va presupune nivelul de severitate implicit error. Utilizarea nivelelor de severitate este descrisă pe
scurt în continuare.
• Nivelul note poate fi utilizat pentru afişarea unor informaŃii despre modul de desfăşurare al simulării.
• Nivelul warning poate fi utilizat în situaŃiile în care simularea poate fi continuată, dar este posibil ca
rezultatele să fie imprevizibile.
• Nivelul error se utilizează atunci când violarea aserŃiunii reprezintă o eroare care determină
funcŃionarea incorectă a modelului, în acest caz execuŃia simulării fiind oprită.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 23

• Nivelul failure se utilizează atunci când violarea aserŃiunii reprezintă o eroare fatală, cum este
împărŃirea la zero sau adresarea unui tablou cu un index care depăşeşte domeniul permis. Şi în acest
caz, execuŃia simulării va fi oprită.

Exemplul 6.32
assert not (R = '1' and S = '1')
report "Ambele semnale R şi S au valoarea '1'"
severity error;

Atunci când ambele semnale R şi S au valoarea '1', se afişează mesajul specificat şi simularea va fi
oprită.
Pentru afişarea unui mesaj în mod necondiŃionat, se va utiliza condiŃia FALSE, de exemplu:
assert (FALSE) report "Start simulare";

Pentru asemenea cazuri, varianta VHDL ’93 a limbajului permite utilizarea clauzei report ca o
instrucŃiune completă, fără clauza assert condiŃie.

ObservaŃii
• InstrucŃiunea assert descrisă este o instrucŃiune secvenŃială, presupunând că ea apare într-un proces
sau subprogram. Există însă şi o versiune concurentă a acestei instrucŃiuni. Aceasta are un format
identic cu versiunea secvenŃială, dar poate apare numai în afara unui proces sau subprogram.
• De obicei, sistemele de sinteză ignoră instrucŃiunea assert.

6.2. InstrucŃiuni concurente


OperaŃiile din sistemele reale se execută în mod concurent. Limbajul VHDL modelează sistemele reale
sub forma unui set de subsisteme care funcŃionează în mod concurent. Fiecare din aceste subsisteme poate fi
specificat sub forma unui proces separat, iar comunicaŃia dintre procese se poate realiza prin semnale.
Complexitatea diferitelor procese poate fi foarte variată, de la o simplă poartă logică până la un procesor.
Modelarea sistemelor reale sub această formă poate fi realizată cu ajutorul instrucŃiunilor concurente.
În această secŃiune se prezintă mai întâi structura şi execuŃia unei arhitecturi, iar apoi sunt descrise
principalele instrucŃiuni concurente ale limbajului VHDL. Cea mai importantă instrucŃiune concurentă este
declaraŃia unui proces. Procesele au fost prezentate în secŃiunea 6.1.1, astfel încât în secŃiunea de faŃă vor fi
prezentate doar principalele caracteristici ale proceselor. Alte instrucŃiuni concurente sunt instrucŃiunea
concurentă de asignare a semnalelor, instrucŃiunea block, instrucŃiunea concurentă assert, instrucŃiunea
concurentă de apel a unei proceduri, instanŃierea unei componente şi instrucŃiunea generate. InstrucŃiunea de
apel a procedurilor va fi prezentată în capitolul 9 în care se descriu subprogramele. InstanŃierea unei componente
şi instrucŃiunea generate vor fi descrise în capitolul 8 dedicat proiectării structurale.

6.2.1. Structura şi execuŃia unei arhitecturi


După cum s-a arătat în capitolul 5, definiŃia unei arhitecturi are două părŃi: o parte declarativă şi o parte
descriptivă. În partea declarativă se pot declara obiecte care sunt interne arhitecturii. Partea descriptivă conŃine
instrucŃiuni concurente. Acestea definesc procesele sau blocurile interconectate care descriu funcŃionarea sau
structura globală a sistemului.
Toate procesele dintr-o arhitectură se execută în paralel unele faŃă de altele, dar instrucŃiunile din cadrul
unui anumit proces se execută secvenŃial. Un proces suspendat este activat din nou atunci când unul din
semnalele din lista sa de sensibilitate îşi modifică valoarea. Atunci când există mai multe procese într-o
arhitectură, la modificarea valorii unui semnal sunt activate toate procesele care conŃin acest semnal în lista lor
de sensibilitate. InstrucŃiunile din cadrul proceselor activate sunt executate secvenŃial, dar independent de
instrucŃiunile din alte procese.
24 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Figura 6.12. Schema unui sumator de 1 bit.

Figura 6.12 prezintă schema unui sumator de 1 bit. În Exemplul 6.33 fiecare poartă din această schemă
este descrisă printr-un proces separat care se execută în mod concurent cu celelalte procese.

Exemplul 6.33
entity add_1 is
port (a, b, cin: in bit;
s, cout: out bit);
end add_1;

architecture procese of add_1 is


signal s1, s2, s3, s4: bit;
begin

p1: process (b, cin)


begin
s1 <= b xor cin;
end process p1;

p2: process (a, b)


begin
s2 <= a and b;
end process p2;

p3: process (a, cin)


begin
s3 <= a and cin;
end process p3;

p4: process (b, cin)


begin
s4 <= b and cin;
end process p4;

p5: process (a, s1)


begin
s <= a xor s1;
end process p5;

p6: process (s2, s3, s4)


begin
cout <= s2 or s3 or s4;
end process p6;

end procese;

ComunicaŃia între procese poate fi realizată cu ajutorul instrucŃiunilor de asignare a semnalelor. Acestea
se pot utiliza atât pentru activarea proceselor, cât şi pentru sincronizarea între procese. Astfel, un semnal poate
aştepta un eveniment asupra unui semnal de intrare, semnal care este asignat într-un alt proces. Acest semnal este
declarat în partea declarativă a arhitecturii, şi astfel este vizibil pentru toate procesele din cadrul arhitecturii.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 25

ObservaŃie
• Pentru comunicaŃia între procese se pot utiliza doar semnalele, nu şi variabilele, deoarece acestea sunt
obiecte locale în procesul în care sunt declarate.

6.2.2. Procese
Procesele sunt compuse din instrucŃiuni secvenŃiale, dar declaraŃiile proceselor reprezintă instrucŃiuni
concurente. DeclaraŃia unui proces a fost prezentată în secŃiunea 6.1.1.1. Se pot formula următoarele
caracteristici ale unui proces:
• Se execută în paralel cu alte procese;
• Nu poate conŃine instrucŃiuni concurente;
• Defineşte o regiune a arhitecturii unde instrucŃiunile se execută secvenŃial;
• Trebuie să conŃină o listă de sensibilitate explicită sau o instrucŃiune wait;
• Permite descrieri funcŃionale, asemănătoare limbajelor de programare;
• Permite accesul la semnalele definite în arhitectura în care apare procesul şi la cele definite în entitatea
cu care este asociată arhitectura.

6.2.3. InstrucŃiuni concurente de asignare a semnalelor


O instrucŃiune concurentă de asignare a valorii unui semnal este echivalentă cu un proces conŃinând
acea instrucŃiune. O asemenea instrucŃiune este executată în paralel cu alte instrucŃiuni concurente sau alte
procese. Există trei tipuri ale instrucŃiunilor concurente de asignare a semnalelor: instrucŃiunea de asignare
simplă, instrucŃiunea de asignare condiŃională şi instrucŃiunea de asignare selectivă. Acestea sunt prezentate în
continuare.

6.2.3.1. InstrucŃiunea de asignare simplă

Această instrucŃiune este versiunea concurentă a instrucŃiunii secvenŃiale de asignare a semnalelor,


având aceeaşi formă cu aceasta. Ca şi în cazul versiunii secvenŃiale, asignarea concurentă defineşte un nou driver
pentru semnalul asignat. Deosebirea faŃă de versiunea secvenŃială este că instrucŃiunea concurentă de asignare
apare în afara unui proces, în cadrul unei arhitecturi. O instrucŃiune concurentă de asignare reprezintă o formă
simplificată de scriere a unui proces, fiind echivalentă cu un proces care conŃine o singură instrucŃiune
secvenŃială de asignare.
Descrierea sumatorului de 1 bit din Exemplul 6.33 poate fi simplificată prin utilizarea instrucŃiunilor
concurente de asignare, după cum se arată în Exemplul 6.34.

Exemplul 6.34
entity add_1 is
port (a, b, cin: in bit;
s, cout: out bit);
end add_1;

architecture concurent of add_1 is


signal s1, s2, s3, s4: bit;
begin
s1 <= b xor cin;
s2 <= a and b;
s3 <= a and cin;
s4 <= b and cin;
s <= a xor s1;
cout <= s2 or s3 or s4;
end concurent;
26 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

După cum se observă din exemplul anterior, instrucŃiunile concurente de asignare apar direct în cadrul
arhitecturii, şi nu în interiorul unui proces. Ordinea în care sunt scrise instrucŃiunile nu are importanŃă. La
simulare toate instrucŃiunile se execută în acelaşi ciclu de simulare.
În cazul proceselor, activarea execuŃiei acestora este determinată de modificarea valorii unui semnal din
lista de sensibilitate a acestora sau de întâlnirea unei instrucŃiuni wait. În cazul instrucŃiunilor concurente de
asignare, modificarea valorii unuia din semnalele care apar în partea dreaptă a asignării activează execuŃia
asignării, fără să se specifice în mod explicit o listă de sensibilitate. Activarea unei instrucŃiuni de asignare este
independentă de activarea altor instrucŃiuni concurente din cadrul arhitecturii.
InstrucŃiunile concurente de asignare se utilizează pentru descrieri de tipul fluxului de date. Prin sinteza
acestor instrucŃiuni se obŃin circuite combinaŃionale.

ObservaŃie
• Dacă într-o arhitectură există mai multe asignări concurente la acelaşi semnal, vor fi create drivere
multiple pentru acel semnal. În asemenea cazuri, trebuie să existe o funcŃie de rezoluŃie predefinită sau
definită de utilizator pentru tipul semnalului respectiv. Spre deosebire de asignările concurente, dacă
într-un proces există mai multe asignări secvenŃiale la acelaşi semnal, va avea efect doar ultima dintre
acestea.

6.2.3.2. InstrucŃiunea de asignare condiŃională

InstrucŃiunea de asignare condiŃională este echivalentă funcŃional cu instrucŃiunea condiŃională if,


având sintaxa următoare:
semnal <= [expresie when condiŃie else ...]
expresie;
Valoarea uneia din expresiile sursă se atribuie semnalului destinaŃie. Expresia atribuită va fi prima a
cărei condiŃie booleană asociată este adevărată. La execuŃia unei instrucŃiuni de asignare condiŃională, condiŃiile
sunt testate în ordinea în care ele sunt scrise. La întâlnirea primei condiŃii care se evaluează la valoarea booleană
TRUE, expresia corespunzătoare acesteia se asignează semnalului destinaŃie. Dacă nici o condiŃie nu se evaluează
la valoarea TRUE, semnalului destinaŃie i se asignează ultima expresie, cea a ultimei clauze else. Dacă există
două sau mai multe condiŃii care se evaluează la valoarea TRUE, va fi luată în considerare doar prima dintre
acestea.
Deosebirile dintre instrucŃiunea de asignare condiŃională şi instrucŃiunea condiŃională if sunt
următoarele:
• InstrucŃiunea de asignare condiŃională este o instrucŃiune concurentă, deci poate fi utilizată într-o
arhitectură, în timp ce instrucŃiunea if este secvenŃială, astfel că poate fi utilizată numai în interiorul
unui proces.
• InstrucŃiunea de asignare condiŃională poate fi utilizată numai pentru asignarea valorii unor semnale, în
timp ce instrucŃiunea if poate fi utilizată pentru execuŃia oricărei instrucŃiuni secvenŃiale.
Exemplul 6.35 defineşte o entitate şi două arhitecturi pentru o poartă SAU EXCLUSIV cu două intrări.
Prima arhitectură utilizează o instrucŃiune de asignare condiŃională, iar a doua utilizează o instrucŃiune if
echivalentă.

Exemplul 6.35
entity xor2 is
port (a, b: in bit;
x: out bit);
end xor2;

architecture arh1_xor2 of xor2 is


begin
x <= '0' when a = b else
'1';
end arh1_xor2;

architecture arh2_xor2 of xor2 is


begin
process (a, b)
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 27

begin
if a = b then x <= '0';
else x <= '1';
end if;
end process;
end arh2_xor2;
InstrucŃiunea de asignare condiŃională este implementată printr-un multiplexor care selectează una din
expresiile sursă. Figura 6.13 prezintă circuitul rezultat pentru următoarea instrucŃiune:
s <= a xor b when c = '1' else
not (a xor b);
Circuitul din Figura 6.13 este cel generat iniŃial de sistemul de sinteză, dar operatorul de egalitate va fi
minimizat ulterior la o simplă conexiune, astfel încât semnalul c să controleze multiplexorul în mod direct.
Exemplul anterior reprezintă forma cea mai simplă a unei instrucŃiuni de asignare condiŃională, în care
există o singură condiŃie testată. Un alt exemplu în care există două condiŃii testate este următorul:
z <= a when s0 = '1' else
b when s1 = '1' else
c;

Figura 6.13. Implementarea unei instrucŃiuni de asignare condiŃională.

CondiŃiile sunt evaluate în ordinea în care sunt scrise, fiind selectată pentru asignare prima expresie a
cărei condiŃie este adevărată. Aceasta echivalează din punct de vedere hardware cu o serie de multiplexoare cu
două căi, prima condiŃie controlând multiplexorul cel mai apropiat de ieşire. Circuitul rezultat pentru acest
exemplu este prezentat în Figura 6.14. Pentru acest circuit, condiŃiile au fost deja optimizate, astfel încât
semnalele s0 şi s1 controlează multiplexoarele în mod direct. Din acest circuit se poate observa că atunci când
s0 este '1', este selectat semnalul a indiferent de valoarea semnalului s1. Dacă s0 este '0', atunci s1 selectează
între intrările b şi c.

Figura 6.14. Implementarea unei instrucŃiuni de asignare condiŃională cu două condiŃii.

Dacă există un număr mare de ramuri ale instrucŃiunii, la implementare rezultă un şir lung de
multiplexoare. De acest aspect trebuie să se Ńină cont la proiectare: cu cât o expresie sursă apare mai târziu în
lista de selecŃie, cu atât semnalele din această expresie vor traversa mai multe multiplexoare în circuitul rezultat
la sinteză.
La implementare, se consideră că fiecare condiŃie dintr-o instrucŃiune de asignare condiŃională este
independentă de celelalte. Aceasta înseamnă că, în cazul în care condiŃiile sunt dependente (de exemplu, se
bazează pe acelaşi semnal), este posibil să nu se realizeze nici o optimizare. De exemplu:
z <= a when sel = '1' else
b when sel = '0' else
c;

În acest exemplu, a doua condiŃie este dependentă de prima. De fapt, în a doua ramură, semnalul sel
poate fi numai '0'. De aceea, a doua condiŃie este redundantă, iar ultima ramură else nu poate fi atinsă. La
28 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

sinteză, această instrucŃiune de asignare condiŃională va fi implementată totuşi prin două multiplexoare, după
cum se ilustrează în Figura 6.15.

Figura 6.15. Implementarea unei instrucŃiuni de asignare condiŃională cu o ramură redundantă.

În cazul unui exemplu simplu cum este cel anterior, este probabil ca sistemul de sinteză să elimine
multiplexorul redundant, dar în cazul unor exemple mai complexe această eliminare nu poate fi garantată.
Motivul pentru care nu se obŃine o implementare optimizată este că, în cazul general, detectarea unui cod VHDL
la care nu se poate ajunge nu este o problemă trivială.
În cazul în care condiŃiile sunt dependente unele de altele, este mai avantajoasă utilizarea unei
instrucŃiuni de asignare selectivă.

6.2.3.3. InstrucŃiunea de asignare selectivă

Ca şi instrucŃiunea de asignare condiŃională, instrucŃiunea de asignare selectivă permite selectarea unei


expresii sursă pe baza unei condiŃii. Deosebirea constă în faptul că instrucŃiunea de asignare selectivă utilizează o
singură condiŃie pentru selecŃia dintre diferite opŃiuni. Această instrucŃiune este echivalentă funcŃional cu
instrucŃiunea secvenŃială case. Sintaxa este următoarea:
with expresie_de_selecŃie select
semnal <= expresie_1 when opŃiuni_1,
...
expresie_n when opŃiuni_n,
[expresie when others];
Semnalului destinaŃie i se atribuie valoarea uneia din expresii. Expresia selectată este prima dintre cele
ale căror opŃiuni includ valoarea expresiei de selecŃie. Sintaxa opŃiunilor este aceeaşi ca şi în cazul instrucŃiunii
case. Astfel, fiecare opŃiune poate fi reprezentată de o valoare individuală sau de un set de valori. În cazul în
care o opŃiune este reprezentată de un set de valori, se pot specifica fie valorile individuale din set, separate prin
simbolul “|”, fie domeniul valorilor, fie o combinaŃie a acestora. Tipul expresiei de selecŃie determină tipul
fiecărei opŃiuni.
Fiecare valoare din domeniul expresiei de selecŃie trebuie să fie acoperită de o opŃiune. Ultima opŃiune
poate fi indicată prin cuvântul cheie others, care specifică toate valorile din domeniul expresiei de selecŃie
rămase neacoperite de opŃiunile anterioare.
Există următoarele restricŃii pentru diferitele opŃiuni:
• Valorile din cadrul opŃiunilor nu se pot suprapune.
• Dacă opŃiunea others nu este prezentă, toate valorile posibile ale expresiei de selecŃie trebuie acoperite
de setul de opŃiuni.

ObservaŃie
• OpŃiunile din cadrul instrucŃiunii de asignare selectivă sunt separate prin virgule.

În Exemplul 6.36 se reia definiŃia porŃii SAU EXCLUSIV cu două intrări, dar în cadrul arhitecturii se
utilizează o instrucŃiune de asignare selectivă. Forma echivalentă a acestei arhitecturi în care s-a utilizat o
instrucŃiune case a fost prezentată în Exemplul 6.23.

Exemplul 6.36
entity xor2 is
port (a, b: in bit;
x: out bit);
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 29

end xor2;

architecture arh_xor2 of xor2 is


signal temp: bit_vector (1 downto 0);
begin
temp <= a & b;
with temp select
x <= '0' when "00",
'1' when "01",
'1' when "10",
'0' when "11";
end arh_xor2;

6.2.3.4. InstrucŃiunea block

O instrucŃiune block defineşte un grup de instrucŃiuni concurente. Această instrucŃiune este utilă pentru
organizarea instrucŃiunilor concurente în mod ierarhic sau pentru partiŃionarea unei liste de conexiuni structurale
în scopul creşterii lizibilităŃii descrierii. Sintaxa instrucŃiunii block este următoarea:
etichetă: block [(expresie_de_gardă)]
[declaraŃii]
begin
instrucŃiuni_concurente
end block [etichetă];
Eticheta obligatorie denumeşte blocul. În partea de declaraŃii se pot declara obiecte locale blocului.
DeclaraŃiile posibile sunt cele care pot apare şi în partea declarativă a unei arhitecturi, şi anume:
• Clauze use;
• DeclaraŃii de porturi şi generice, ca şi declaraŃii pentru maparea acestora;
• DeclaraŃii şi corpuri de subprograme;
• DeclaraŃii de tipuri şi subtipuri;
• DeclaraŃii de constante, variabile şi semnale;
• DeclaraŃii de componente;
• DeclaraŃii de fişiere, atribute şi configuraŃii.
Ordinea instrucŃiunilor concurente dintr-un bloc nu este semnificativă, deoarece toate instrucŃiunile sunt
întotdeauna active. Într-un bloc pot fi declarate alte blocuri, pe mai multe nivele ierarhice. Obiectele declarate
într-un bloc sunt vizibile în acel bloc şi în toate blocurile interioare. Atunci când într-un bloc interior se declară
un obiect cu acelaşi nume ca şi un obiect dintr-un bloc exterior, este valabilă declaraŃia din blocul interior.
Exemplul 6.37 ilustrează utilizarea blocurilor pe mai multe nivele ierarhice.

Exemplul 6.37
B1: block
signal s: bit; -- declaraŃia "s" în blocul B1
begin
s <= a and b; -- "s" din blocul B1
B2: block
signal s: bit; -- declaraŃia "s" în blocul B2
begin
s <= c and d; -- "s" din blocul B2
B3: block
begin
x <= s; -- "s" din blocul B2
end block B3;
end block B2;
y <= s; -- "s" din blocul B1
end block B1;

Introducerea blocurilor în cadrul unei descrieri nu afectează execuŃia unui model la simulare, ci are doar
rol de organizare a descrierii.
La declararea unui bloc se poate specifica o expresie booleană, numită expresie de gardă. Această
expresie, specificată în paranteze după cuvântul cheie block, crează în mod implicit un semnal boolean numit
guard, care se poate utiliza pentru controlul unor operaŃii din cadrul blocului. Acest semnal poate fi citit ca orice
30 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

alt semnal din cadrul instrucŃiunii block, dar nu poate fi actualizat printr-o instrucŃiune de asignare. De fiecare
dată când apare o tranzacŃie asupra unuia din semnalele dintr-o expresie de gardă, expresia este evaluată şi
semnalul guard este actualizat imediat. Acest semnal ia valoarea TRUE dacă valoarea expresiei de gardă este
adevărată şi FALSE în caz contrar.
Semnalul guard poate fi declarat şi în mod explicit ca un semnal de tip boolean în cadrul instrucŃiunii
block. Avantajul acestei declarări explicite este că se poate utiliza un algoritm mai complex pentru controlul
semnalului guard decât cel permis de o expresie booleană. În particular, se poate utiliza un proces separat
pentru controlul acestui semnal.
Dacă într-un bloc nu se specifică o expresie de gardă şi semnalul guard nu este declarat în mod
explicit, atunci acest semnal are întotdeauna valoarea TRUE.
Semnalul guard poate fi utilizat pentru controlul instrucŃiunilor de asignare a semnalelor din cadrul
blocului. O asemenea instrucŃiune de asignare conŃine cuvântul cheie guarded după simbolul de asignare, care
determină ca execuŃia instrucŃiunii de asignare să fie condiŃională:
semnal <= guarded expresie;
Această asignare se execută numai dacă semnalul guard al blocului care conŃine expresia de gardă are
valoarea TRUE.
În Exemplul 6.38, semnalului out1 i se va asigna valoarea not in1 numai dacă valoarea expresiei
clk'event and clk = '1' va fi adevărată.

Exemplul 6.38
front_crescator: block (clk'event and clk = '1')
begin
out1 <= guarded not in1 after 5 ns;
...
end block front_crescator;

În Exemplul 6.39, semnalul guard este declarat in mod explicit, astfel încât i se poate asigna o valoare
ca şi oricărui alt semnal.

Exemplul 6.39
UAL: block
signal guard: boolean := FALSE;
begin
out1 <= guarded not in1 after 5 ns;
...
p1: process
begin
guard <= TRUE;
...
end process p1;
end block UAL;

ObservaŃii
• În general, sistemele de sinteză nu permit utilizarea blocurilor cu expresii de gardă. Un asemenea bloc
este echivalent cu un proces cu o listă de sensibilitate şi care conŃine instrucŃiuni condiŃionale. Se poate
utiliza un asemenea proces în locul unui bloc cu o expresie de gardă.
• De obicei, blocurile simple sunt ignorate de sistemele de sinteză.
• Deşi blocurile se pot utiliza pentru partiŃionarea descrierilor, limbajul VHDL permite utilizarea unui
mecanism mai puternic pentru partiŃionare, şi anume instanŃierea componentelor. Această instanŃiere va
fi prezentată în capitolul 8.

6.2.3.5. InstrucŃiunea concurentă assert

Această instrucŃiune este versiunea concurentă a instrucŃiunii secvenŃiale assert, având aceeaşi sintaxă
ca şi versiunea sa secvenŃială:
assert condiŃie
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 31

[report şir_de_caractere]
[severity nivel_de_severitate];

InstrucŃiunea concurentă assert se va executa ori de câte ori se modifică unul din semnalele din cadrul
expresiei condiŃionale, spre deosebire de instrucŃiunea secvenŃială assert, care se va executa atunci când se
ajunge la această instrucŃiune în cadrul unui proces sau subprogram.

6.3. Descrierea unor circuite combinaŃionale

6.3.1. Multiplexoare
Pentru descrierea multiplexoarelor se pot utiliza diferite metode. Exemplul 6.40 prezintă descrierea
multiplexorului 4:1 pentru magistrale de 4 biŃi din Figura 6.16 utilizând o instrucŃiune de asignare selectivă.

Figura 6.16. Schema unui multiplexor 4:1 pentru magistrale de 4 biŃi.

Exemplul 6.40
library ieee;
use ieee.std_logic_1164.all;
entity mux is
port (a, b, c, d: in std_logic_vector (3 downto 0);
s: in std_logic_vector (1 downto 0);
x: out std_logic_vector (3 downto 0));
end mux;

architecture arh_mux of mux is


begin
with s select
x <= a when "00",
b when "01",
c when "10",
d when "11",
d when others;
end arh_mux;

Motivul pentru care se utilizează cuvântul cheie others este că semnalul de selecŃie s este de tip
std_logic_vector şi există nouă valori posibile ale unui obiect de acest tip. Toate valorile posibile ale
semnalului de selecŃie trebuie acoperite. În cazul în care nu s-ar fi utilizat opŃiunea others, doar patru din cele
81 de valori posibile ar fi acoperite de setul de opŃiuni. Alte valori posibile ale semnalului s sunt, de exemplu,
"1X", "UX", "Z0", "U-". Pentru sinteză "11" este singura valoare utilă, însă pentru simulare semnalul s poate
avea alte 77 de valori posibile. Se poate utiliza şi valoarea metalogică "--" pentru asignarea unei valori
indiferente semnalului x.
Multiplexorul 4:1 poate fi descris cu ajutorul unei instrucŃiuni if în modul arătat în Exemplul 6.41.

Exemplul 6.41
architecture arh_mux of mux is
begin
mux4_1: process (a, b, c, d, s)
begin
if s = "00" then
x <= a;
32 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

elsif s = "01" then


x <= b;
elsif s = "10" then
x <= c;
else
x <= d;
end if;
end process mux4_1;
end arh_mux;

Deoarece condiŃiile implică valori mutual exclusive ale semnalului s, prin sinteza acestei descrieri se
obŃine acelaşi circuit ca şi în cazul utilizării unei instrucŃiuni de asignare selectivă. Însă, deoarece condiŃiile
conŃin o prioritate, instrucŃiunea if nu este avantajoasă atunci când condiŃiile implică semnale multiple care sunt
mutual exclusive. Utilizarea unei instrucŃiuni if în aceste cazuri poate determina generarea unei logici
suplimentare pentru a asigura faptul că precedentele condiŃii nu sunt adevărate. În locul unei instrucŃiuni if, este
mai avantajoasă utilizarea unei ecuaŃii booleene sau a unei instrucŃiuni case.

6.3.2. Codificatoare prioritare


Un exemplu de codificator prioritar este prezentat în Figura 6.17.

Figura 6.17. Schema unui codificator prioritar.

Acest codificator prioritar poate fi descris în mod concis cu ajutorul unei instrucŃiuni de asignare
condiŃională, ca în Exemplul 6.42.

Exemplul 6.42
library ieee;
use ieee.std_logic_1164.all;
entity codif_prioritar is
port (a, b, c, d: in std_logic;
w, x, y, z: in std_logic;
j: out std_logic);
end codif_prioritar;

architecture prioritar of codif_prioritar is


begin
j <= w when a = '1' else
x when b = '1' else
y when c = '1' else
z when d = '1' else
'0';
end prioritar;

InstrucŃiunea when-else din exemplul precedent indică faptul că semnalului j i se asignează valoarea
semnalului w atunci când a este '1', chiar dacă b, c sau d sunt '1'. Semnalul b este prioritar faŃă de semnalele c şi
d, iar semnalul c este prioritar faŃă de semnalul d. Dacă semnalele a, b, c şi d sunt mutual exclusive (deci, se
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 33

cunoaşte că numai unul din acestea va fi activ la un moment dat), atunci este mai avantajoasă descrierea din
Exemplul 6.43.

Exemplul 6.43
library ieee;
use ieee.std_logic_1164.all;
entity fara_prioritate is
port (a, b, c, d: in std_logic;
w, x, y, z: in std_logic;
j: out std_logic);
end fara_prioritate;

architecture fara_prioritate of fara_prioritate is


begin
j <= (a and w) or (b and x) or (c and y) or (d and z);
end fara_prioritate;

Logica generată prin sinteza descrierii din Exemplul 6.43 necesită porŃi ŞI cu doar două intrări. Deşi în
cazul circuitelor CPLD (Complex Programmable Logic Device) porŃile ŞI cu un număr mai mare de intrări nu
necesită, de obicei, resurse suplimentare, în cazul circuitelor FPGA (Field-Programmable Gate Array) aceste
porŃi pot necesita celule logice şi nivele logice suplimentare. Descrierile din Exemplul 6.42 şi Exemplul 6.43 nu
sunt echivalente funcŃional, această echivalenŃă existând doar în cazul în care semnalele a, b, c şi d sunt mutual
exclusive. În acest caz, descrierea din Exemplul 6.43 generează o logică echivalentă cu un număr mai redus de
resurse.

6.4. Descrierea unor circuite secvenŃiale

6.4.1. Circuite secvenŃiale sincrone şi asincrone


Circuitele secvenŃiale reprezintă acea categorie de circuite logice care cuprind elemente de memorare.
Efectul de memorare se datorează unor legături inverse (bucle de reacŃie) prezente în schemele logice ale acestor
circuite. Semnalele generate la ieşirile unui circuit secvenŃial depind atât de semnalele de intrare, cât şi de starea
circuitului.
Starea prezentă a circuitului este determinată de o stare anterioară şi de valorile semnalelor de intrare. În
cazul circuitelor secvenŃiale sincrone, modificarea stării se poate realiza la momente bine definite de timp sub
controlul unui semnal de ceas. În cazul circuitelor secvenŃiale asincrone, modificarea stării poate fi cauzată de
schimbarea aleatoare în timp a valorii unui semnal de intrare. Comportamentul unui circuit asincron este în
general mai puŃin sigur, evoluŃia stării fiind influenŃată şi de timpii de întârziere ai componentelor circuitului.
Trecerea între două stări stabile se poate realiza printr-o succesiune de stări instabile, aleatoare.
Circuitele secvenŃiale sincrone sunt mai fiabile şi au un comportament predictiv. Toate elementele de
memorare ale unui circuit sincron îşi modifică simultan starea, ceea ce elimină apariŃia unor stări intermediare
instabile. Prin testarea semnalelor de intrare la momente bine definite de timp se reduce influenŃa întârzierilor şi
a eventualelor zgomote.
Există două tehnici de proiectare a circuitelor secvenŃiale: Mealy şi Moore. În cazul circuitelor
secvenŃiale Mealy, semnalele de ieşire depind atât de starea curentă, cât şi de intrările prezente. În cazul
circuitelor secvenŃiale Moore, ieşirile sunt dependente numai de starea curentă, fără să depindă în mod direct de
intrări. Metoda Mealy permite implementarea unui anumit circuit printr-un număr minim de elemente de
memorare (bistabile), însă eventualele variaŃii necontrolate ale semnalelor de intrare se pot transmite semnalelor
de ieşire. Proiectarea prin metoda Moore necesită mai multe elemente de memorare pentru acelaşi tip de
comportament, dar funcŃionarea circuitului este mai sigură.

6.4.2. Bistabile
În Exemplul 6.44 se descrie un bistabil sincron de tip D acŃionat pe frontul crescător al semnalului de
ceas (Figura 6.18).
34 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Figura 6.18. Simbolul unui bistabil de tip D.

Exemplul 6.44
library ieee;
use ieee.std_logic_1164.all;
entity bist_d is
port (d: in std_logic;
clk: in std_logic;
q: out std_logic);
end bist_d;

architecture exemplu of bist_d is


begin
process (clk)
begin
if (clk'event and clk = '1') then
q <= d;
end if;
end process;
end exemplu;

Procesul utilizat pentru descrierea bistabilului este sensibil numai la modificările semnalului de ceas
clk. TranziŃia semnalului de intrare d nu determină activarea procesului. Expresia clk'event şi lista de
sensibilitate sunt redundante, deoarece ambele detectează modificarea semnalului de ceas. Unele sisteme de
sinteză ignoră însă lista de sensibilitate a procesului, motiv pentru care trebuie inclusă expresia clk'event
pentru descrierea evenimentelor acŃionate pe frontul semnalului de ceas.
Pentru descrierea unui circuit latch acŃionat pe nivel (Figura 6.19), se elimină condiŃia clk'event şi se
inserează intrarea de date d în lista de sensibilitate a procesului, după cum se arată în Exemplul 6.45.

Figura 6.19. Simbolul unui circuit latch de tip D.

Exemplul 6.45
architecture exemplu of latch_d is
begin
process (clk, d)
begin
if (clk = '1') then
q <= d;
end if;
end process;
end exemplu;

În exemplele 6.44 şi 6.45 nu există o condiŃie else. Fără această condiŃie, este specificat în mod
implicit un element de memorie (care va păstra valoarea semnalului q). Cu alte cuvinte, următorul fragment:
if (clk'event and clk = '1') then
q <= d;
end if;
are aceeaşi semnificaŃie pentru simulare ca şi fragmentul:
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 35

if (clk'event and clk = '1') then


q <= d;
else
q <= q;
end if;
Aceasta este în concordanŃă cu modul în care funcŃionează un bistabil de tip D. Cele mai multe sisteme
de sinteză nu permit utilizarea unei expresii else după condiŃia if (clk'event and clk = '1'), deoarece
implementarea unei asemenea descrieri poate fi ambiguă.
După cum s-a arătat în secŃiunea 6.1.4.3, în cazul în care o instrucŃiune condiŃională nu are toate
alternativele specificate, la sinteză se generează un element de memorare (bistabil). Pentru a evita generarea unor
elemente de memorare (atunci când nu este necesar), trebuie să se asigneze valori variabilelor sau semnalelor în
fiecare ramură condiŃională.

6.4.3. Registre
În Exemplul 6.46 se descrie un registru de 8 biŃi printr-un proces similar celui din Exemplul 6.44, cu
deosebirea că d şi q sunt vectori.

Exemplul 6.46
library ieee;
use ieee.std_logic_1164.all;
entity reg8 is
port (d: in std_logic_vector (7 downto 0);
clk: in std_logic;
q: out std_logic_vector (7 downto 0));
end reg8;

architecture ex_reg of reg8 is


begin
process (clk)
begin
if (clk'event and clk = '1') then
q <= d;
end if;
end process;
end ex_reg;

6.4.4. Numărătoare
În Exemplul 6.47 se descrie un numărător de 3 biŃi.

Exemplul 6.47
library ieee;
use ieee.std_logic_1164.all;
entity num3 is
port (clk: in std_logic;
num: buffer integer range 0 to 7);
end num3;

architecture num3_integer of num3 is


begin
count: process (clk)
begin
if (clk'event and clk = '1') then
num <= num + 1;
end if;
end process count;
end num3_integer;
36 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

În exemplul anterior, operatorul de adunare este utilizat pentru semnalul num, care este de tip integer.
Majoritatea sistemelor de sinteză permit această utilizare, convertind tipul integer la tipul bit_vector sau
std_logic_vector. Utilizarea tipului integer pentru porturi pune însă unele probleme:

1) Pentru a utiliza valoarea num într-o altă porŃiune a proiectului pentru care interfaŃa are porturi de tip
std_logic, trebuie efectuată o conversie de tip.
2) Vectorii aplicaŃi în timpul simulării codului sursă nu pot fi utilizaŃi pentru simularea modelului generat
în urma sintezei. Pentru codul sursă, vectorii trebuie să fie valori întregi. Modelul generat în urma
sintezei necesită vectori de tip std_logic.
Deoarece operatorul nativ + al limbajului VHDL nu este definit pentru tipurile bit sau std_logic,
acest operator trebuie redefinit înainte de adunarea operanzilor care au aceste tipuri. Standardul IEEE 1076.3
defineşte funcŃii pentru redefinirea operatorului + pentru următoarele perechi de operanzi: (unsigned,
unsigned), (unsigned, integer), (signed, signed) şi (signed, integer). Aceste funcŃii sunt definite în
pachetul numeric_std al standardului 1076.3.
Exemplul 6.48 reprezintă Exemplul 6.47 modificat pentru a se utiliza tipul unsigned pentru ieşirea
numărătorului.

Exemplul 6.48
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity num3 is
port (clk: in std_logic;
num: buffer unsigned (3 downto 0));
end num3;

architecture num3_unsigned of num3 is


begin
count: process (clk)
begin
if (clk'event and clk = '1') then
num <= num + 1;
end if;
end process count;
end num3_unsigned;

De obicei, sistemele de sinteză pun la dispoziŃie pachete suplimentare care redefinesc operatorii pentru
tipul std_logic. Deşi acestea nu sunt pachete standard, ele se utilizează adesea de către proiectanŃi, deoarece
permit de obicei operaŃii aritmetice şi relaŃionale cu tipul std_logic, din acest punct de vedere fiind chiar mai
utile decât pachetul numeric_std. De asemenea, aceste pachete nu necesită utilizarea a două tipuri
suplimentare (signed, unsigned) în plus faŃă de tipul std_logic_vector şi nici a funcŃiilor necesare
conversiei între aceste tipuri. La utilizarea unuia din aceste pachete pentru operaŃiile aritmetice, sistemul de
sinteză va utiliza pentru tipul std_logic_vector o reprezentare fără semn sau una cu semn (de obicei în C2),
şi va genera componentele aritmetice corespunzătoare.

6.4.5. Resetarea componentelor sincrone


Exemplele anterioare nu fac referire la resetarea componentelor descrise sau la condiŃiile iniŃiale.
Standardul VHDL nu specifică faptul că un circuit trebuie resetat sau iniŃializat. Pentru simulare, standardul
specifică faptul că, dacă un semnal nu este iniŃializat explicit, acesta va fi iniŃializat cu valoarea având atributul
'left a tipului semnalului respectiv. Pentru ca circuitele reale să fie aduse într-o stare cunoscută la iniŃializare,
trebuie utilizate semnale de resetare şi setare (preset).
Figura 6.20 ilustrează un bistabil de tip D cu un semnal de resetare asincronă. Acest bistabil poate fi
descris în modul prezentat în Exemplul 6.49.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 37

Figura 6.20. Simbolul unui bistabil de tip D cu un semnal de resetare asincronă.

Exemplul 6.49
architecture exemplu_r of bist_d is -- 1
begin -- 2
process (clk, reset) -- 3
begin -- 4
if (reset = '1') then -- 5
q <= '0'; -- 6
elsif rising_edge (clk) then -- 7
q <= d; -- 8
end if; -- 9
end process; -- 10
end exemplu_r; -- 11

Dacă semnalul reset este activat, semnalul q va fi setat la '0', indiferent de valoarea semnalului de
ceas. FuncŃia rising_edge este definită în pachetul std_logic_1164, având rolul de a detecta frontul
crescător al unui semnal. Această funcŃie se poate utiliza în locul expresiei (clk'event and clk = '1'), dacă
semnalul clk este de tip std_logic. În acelaşi pachet este definită şi funcŃia falling_edge, care detectează
fronturile descrescătoare ale semnalelor. Aceste funcŃii sunt preferate de către unii proiectanŃi deoarece la
simulare funcŃia rising_edge, de exemplu, va asigura că tranziŃia este de la '0' la '1', şi nu va Ńine cont de alte
tranziŃii cum este cea de la 'U' la '1'.
Pentru a descrie un bistabil cu un semnal de setare asincronă, liniile 5-7 din exemplul anterior se
modifică astfel:
if (set = '1') then -- 5
q <= '1'; -- 6
elsif rising_edge (clk) then -- 7
Se pot utiliza semnale de resetare (sau de setare) sincrone prin includerea condiŃiei respective în
interiorul porŃiunii procesului care este sincronă cu ceasul, după cum se indică în Exemplul 6.50.

Exemplul 6.50
architecture exemplu_r_sinc of bist_d is
begin
process (clk)
begin
if rising_edge (clk) then
if (reset = '1') then
q <= '0';
else
q <= d;
end if;
end if;
end process;
end exemplu_r_sinc;

ExecuŃia procesului din exemplul anterior depinde numai de modificările semnalului de ceas. În urma
sintezei se generează un bistabil D care resetat în mod sincron atunci când semnalul reset este activ şi apare un
front crescător al semnalului de ceas. Deoarece bistabilele circuitelor PLD nu dispun de obicei de intrări de setare
sau resetare sincronă, implementarea acestor intrări necesită utilizarea unor resurse logice suplimentare (Figura
6.21).
38 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

Figura 6.21. Resurse logice suplimentare necesare pentru un semnal de resetare sincronă.

Se pot utiliza de asemenea combinaŃii de semnale sincrone şi asincrone de resetare (sau setare). Uneori
sunt necesare două semnale asincrone: atât un semnal de resetare, cât şi unul de setare. Exemplul 6.51 prezintă
un numărător de 8 biŃi cu semnale asincrone de resetare şi setare.

Exemplul 6.51
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity num8 is
port (clk: in std_logic;
reset, set: in std_logic;
enable, load: in std_logic;
data: in unsigned (7 downto 0);
num: buffer unsigned (7 downto 0));
end num8;

architecture arh_num8 of num8 is


begin
count: process (reset, set, clk)
begin
if (reset = '1') then
num <= (others => '0');
elsif (set = '1') then
num <= (others => '1');
elsif (clk'event and clk = '1') then
if (load = '1') then
num <= data;
elsif (enable = '1') then
num <= num + 1;
end if;
end if;
end process count;
end arh_num8;

În exemplul anterior, ambele semnale reset şi set sunt utilizate pentru asignarea asincronă a unor
valori la registrele numărătorului. CombinaŃia de semnale de resetare şi setare din acest exemplu ridică o
problemă legată de sinteză. ConstrucŃia if-then-else utilizată în cadrul procesului implică o precedenŃă –
faptul că numărătorului trebuie să i se asigneze valoarea "11111111" numai atunci când semnalul set este
activ şi semnalul reset nu este activ. Logica din Figura 6.22(a) asigură această condiŃie.

Figura 6.22. Rezultatul sintezei descrierii din Exemplul 6.51: (a) logica suplimentară asigură ca semnalul reset
să fie dominant; (b) rezultatul dacă se presupune că semnalul reset este dominant.

Există posibilitatea ca aceasta să nu reprezinte comportarea dorită. Unele sisteme de sinteză pot
recunoaşte faptul că acesta nu reprezintă efectul dorit şi că prin construcŃia bistabilelor este dominant fie
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 39

semnalul reset, fie semnalul set. Astfel, în funcŃie de algoritmul utilizat de programul de sinteză, descrierea
din Exemplul 6.51 va genera fie logica din Figura 6.22(a), fie cea din Figura 6.22(b). Multe circuite CPLD care
permit resetarea sau setarea prin termeni produs pot implementa ambele variante. De asemenea, majoritatea
circuitelor FPGA dispun de resursele necesare pentru implementarea resetării sau setării prin termeni produs.
Totuşi, în timp ce majoritatea circuitelor FPGA permit resetarea sau setarea eficientă prin semnale globale, de
obicei acestea nu dispun de resurse pentru resetarea sau setarea eficientă prin termeni produs, caz în care
implementarea din Figura 6.22(b) este preferată.
În toate exemplele anterioare în care există semnale de resetare sau setare s-a utilizat instrucŃiunea if
sau funcŃia rising_edge pentru descrierea circuitelor sincrone. Pentru descrierea acestor circuite se poate
utiliza şi instrucŃiunea wait until, dar în acest caz semnalele de resetare şi setare trebuie să fie sincrone.
Aceasta deoarece pentru descrierile destinate sintezei instrucŃiunea wait trebuie să fie prima din cadrul unui
proces, astfel încât toate instrucŃiunile care urmează vor descrie o logică sincronă.

6.4.6. Buffere cu trei stări şi semnale bidirecŃionale


Majoritatea circuitelor programabile dispun de ieşiri cu trei stări sau semnale bidirecŃionale de I/E. În
plus, anumite circuite dispun de buffere interne cu trei stări. Un semnal cu trei stări poate avea valorile '0', '1'
şi 'Z', toate acestea fiind permise de tipul std_logic.
Exemplul 6.52 prezintă descrierea modificată a numărătorului din Exemplul 6.51 pentru a utiliza ieşiri
cu trei stări. Acest numărător nu dispune de un semnal de setare asincronă. De data acesta s-a utilizat pachetul
std_arith şi tipul std_logic_vector pentru data şi num.

Exemplul 6.52
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_arith.all;
entity num8 is
port (clk, reset: in std_logic;
enable, load: in std_logic;
oe: in std_logic;
data: in std_logic_vector (7 downto 0);
num: buffer std_logic_vector (7 downto 0));
end num8;

architecture arh_num8 of num8 is


signal num_tmp: std_logic_vector (7 downto 0);
begin
count: process (reset, clk)
begin
if (reset = '1') then
num <= (others => '0');
elsif rising_edge (clk) then
if (load = '1') then
num_tmp <= data;
elsif (enable = '1') then
num_tmp <= num_tmp + 1;
end if;
end if;
end process count;

oep: process (oe, num_tmp)


begin
if (oe = '0') then
num <= (others => 'Z');
else
num <= num_tmp;
end if;
end process oep;

end arh_num8;

În această descriere se utilizează două semnale suplimentare faŃă de descrierea din Exemplul 6.51:
semnalul oe, prevăzut pentru controlul ieşirilor cu trei stări, şi semnalul local num_tmp declarat în cadrul
40 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

arhitecturii. Procesul etichetat cu oep este utilizat pentru a descrie ieşirile cu trei stări ale numărătorului. Dacă
semnalul oe nu este activat, ieşirile sunt trecute în starea de înaltă impedanŃă. Descrierea procesului oep este în
concordanŃă cu operarea unui buffer cu trei stări (Figura 6.23).

Figura 6.23. Buffer cu trei stări.

Numărătorul din exemplele precedente poate fi modificat astfel încât pentru ieşirile acestuia să se
utilizeze semnale bidirecŃionale. În acest caz, numărătorul poate fi încărcat cu valoarea curentă a ieşirilor
acestuia, ceea ce înseamnă că valoarea încărcată atunci când semnalul load este activ va fi valoarea precedentă
a numărătorului sau o valoare aplicată din exterior, în funcŃie de starea semnalului oe.
În Exemplul 6.53, semnalul de validare a ieşirilor unui buffer cu trei stări este definit în mod implicit.

Exemplul 6.53
mux: process (adr_lin, adr_col, stare_prez)
begin
if (stare_prez = linie or stare_prez = RAS) then
dram <= adr_lin;
elsif (stare_prez = coloana or stare_prez = CAS) then
dram <= adr_col;
else
dram <= (others => 'Z');
end if;
end process mux;

Bufferele cu trei stări ale semnalului dram sunt validate dacă valoarea pentru stare_prez este linie,
RAS, coloana sau CAS. Pentru orice altă valoare a semnalului stare_prez, aceste buffere nu sunt validate.
În exemplele anterioare, pentru bufferele cu trei stări s-au utilizat descrieri funcŃionale. Pentru generarea
acestor buffere se pot utiliza şi descrieri structurale, cum este construcŃia for generate. Această construcŃie
va fi descrisă în capitolul 8.

6.5. AplicaŃii
6.5.1. IdentificaŃi şi corectaŃi erorile din următoarea descriere:
library ieee; -- 1
use ieee.std_logic.all; -- 2
entity t_c is -- 3
port (clock, reset, enable: in bit; -- 4
data: in std_logic_vector (7 downto 0); -- 5
egal, term_cnt: out std_logic); -- 6
end t_c; -- 7
architecture t_c of t_c is -- 8
signal num: std_logic_vector (7 downto 0); -- 9
begin -- 10
comp: process -- 11
begin -- 12
if data = num then -- 13
egal = '1'; -- 14
end if; -- 15
end process; -- 16
-- 17
count: process (clk) -- 18
begin -- 19
if reset = '1' then -- 20
num <= "111111111"; -- 21
elsif rising_edge (clock) then -- 22
num <= num + 1; -- 23
end if; -- 24
end process; -- 25
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 41

-- 26
term_cnt <= 'z' when enable = '0' else -- 27
'1' when num = "1-------" else -- 28
'0'; -- 29
end t_c; -- 30

UtilizaŃi sistemul Active-HDL pentru compilarea cu succes a acestei descrieri.


6.5.2. AnalizaŃi exemplele prezentate care se referă la instrucŃiunile secvenŃiale. SimulaŃi descrierea
comparatorului (Exemplul 6.12), a numărătorului (Exemplul 6.21), a circuitului pentru compararea biŃilor de
acelaşi rang a doi vectori (Exemplul 6.26), a circuitului pentru contorizarea biŃilor de '1' ai unui vector (Exemplul
6.27).
6.5.3. ScrieŃi o secvenŃă pentru setarea semnalului x la valoarea funcŃiei ŞI logic între toate liniile unei
magistrale de 8 biŃi a_bus[7:0].
6.5.4. ModificaŃi următoarea secvenŃă pentru a utiliza o instrucŃiune de asignare condiŃională:
process (a, b, j, k)
begin
if a = '1' and b = '0' then
pas <= "0100";
elsif a = '1' then
pas <= j;
elsif b = '1' then
pas <= k;
else
pas <= "----";
end if;
end process;

6.5.5. TransformaŃi următoarea secvenŃă într-o instrucŃiune case:


with stare select
data <= "0000" when inactiv | terminat,
"1111" when creste,
"1010" when mentine,
"0101" when scade,
"----" when others;

6.5.6. TransformaŃi următoarea secvenŃă în două instrucŃiuni de asignare selectivă:


case stare is
when inactiv => a <= "11"; b <= "00";
when terminat | creste => a <= "01"; b <= "--";
when mentine | scade => a <= "10"; b <= "11";
when others => a <= "11"; b <= "01";
end case;

6.5.7. RescrieŃi următoarea secvenŃă utilizând o instrucŃiune condiŃională if:


iesire <= a when stare = inactiv else
b when stare = receptie else
c when stare = transmisie else
d;
6.5.8. SimulaŃi funcŃionarea circuitelor combinaŃionale descrise în exemplele 6.40, 6.41, 6.42 şi 6.43.
6.5.9. RealizaŃi un comparator de 4 biŃi cu trei ieşiri (egal, mai mic, mai mare) utilizând:
a. Operatori logici;
b. Operatori relaŃionali;
c. InstrucŃiunea de asignare selectivă;
d. InstrucŃiunea condiŃională if.
CompilaŃi descrierile comparatorului şi simulaŃi funcŃionarea acestora.
6.5.10. DescrieŃi un multiplexor 4:1 de 8 biŃi utilizând o instrucŃiune case. Intrările multiplexorului
sunt a[7:0], b[7:0], c[7:0], d[7:0], s[1:0], iar ieşirile sunt q[7:0].
42 Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL

6.5.11. RealizaŃi un decodificator din codul BCD pentru afişajul cu 7 segmente. Intrările
decodificatorului sunt bcd[3:0], iar ieşirile sunt led[6:0].
6.5.12. ProiectaŃi o memorie FIFO cu capacitatea de 8 cuvinte de câte 9 biŃi. Schema bloc a acestei
memorii FIFO este prezentată în Figura 6.24.

Figura 6.24. Schema bloc a unei memorii FIFO.

La activarea semnalului de citire rd trebuie să se valideze ieşirea memoriei, data_out (9 biŃi). Atunci
când semnalul de citire nu este activat, ieşirea memoriei trebuie adusă în starea de înaltă impedanŃă. La activarea
semnalului de scriere wr trebuie înscrisă valoarea de la intrarea data_in a memoriei într-unul din cele 8 registre.
Pentru evidenŃa citirii şi a scrierii există un pointer de citire, respectiv de scriere, acestea indicând registrul care
trebuie citit, respectiv registrul care trebuie înscris. Pentru incrementarea pointerilor de citire şi de scriere se
utilizează semnalele rdinc, respectiv wrinc. Semnalele rdptrclr şi wrptrclr resetează pointerii de citire şi de
scriere pentru ca aceştia să adreseze primul registru al memoriei FIFO.
6.5.13. CompilaŃi descrierea registrului de 8 biŃi din Exemplul 6.46 şi simulaŃi funcŃionarea acestui
registru.
6.5.14. ModificaŃi descrierea registrului de 8 biŃi din Exemplul 6.46 astfel încât să se utilizeze două
semnale suplimentare de intrare, reset şi init. La activarea semnalului reset, registrul va fi resetat la
"00000000" în mod asincron. La activarea semnalului init, registrul va fi setat la "11111111" în mod
sincron. VerificaŃi apoi funcŃionarea registrului.
6.5.15. CompilaŃi descrierea numărătorului de 3 biŃi din Exemplul 6.47 şi verificaŃi funcŃionarea
numărătorului. ModificaŃi apoi descrierea pentru a utiliza tipul std_logic_vector pentru vectorul de ieşire
num.
6.5.16. ModificaŃi descrierea numărătorului de 8 biŃi având ieşiri cu trei stări din Exemplul 6.52, astfel
încât să se utilizeze o instrucŃiune de asignare condiŃională în locul procesului oep. AdăugaŃi un semnal de ieşire
cu trei stări numit coliziune, care va fi activat atunci când semnalele enable şi load sunt ambele active, cu
condiŃia ca ieşirile numărătorului să fie activate prin semnalul oe.
Structura sistemelor de calcul – InstrucŃiuni secvenŃiale şi concurente în limbajul VHDL 43

6.5.17. ModificaŃi descrierea numărătorului de 8 biŃi din Exemplul 6.52, astfel încât pentru ieşirile
acestuia să se utilizeze semnale bidirecŃionale. Numărătorul va fi încărcat cu valoarea curentă a ieşirilor acestuia,
în locul vectorului de intrare data.
6.5.18. ProiectaŃi un circuit de înmulŃire binară pentru numere de câte 8 biŃi reprezentate în mărime şi
semn utilizând metoda directă. UtilizaŃi procese sau instrucŃiuni concurente de asignare a semnalelor pentru
fiecare element al circuitului.
6.5.19. ProiectaŃi un circuit de înmulŃire binară pentru numere de câte 8 biŃi reprezentate în complement
faŃă de 2 utilizând metoda Booth. UtilizaŃi procese sau instrucŃiuni concurente de asignare a semnalelor pentru
fiecare element al circuitului.
6.5.20. ProiectaŃi un circuit de înmulŃire binară pentru numere fără semn de câte 16 biŃi utilizând
înmulŃirea pe grupe de doi biŃi. UtilizaŃi procese sau instrucŃiuni concurente de asignare a semnalelor pentru
fiecare element al circuitului.
6.5.21. ProiectaŃi un circuit de împărŃire binară pentru numere reprezentate în mărime şi semn utilizând
metoda fără refacerea restului parŃial. DeîmpărŃitul este un număr de 16 biŃi, iar împărŃitorul este un număr de 8
biŃi. UtilizaŃi procese sau instrucŃiuni concurente de asignare a semnalelor pentru fiecare element al circuitului.
6.5.22. ProiectaŃi un circuit de înmulŃire zecimală pentru numere de câte 4 cifre utilizând metoda
componenŃilor din dreapta şi din stânga. UtilizaŃi procese sau instrucŃiuni concurente de asignare a semnalelor
pentru fiecare element al circuitului.
6.5.23. DescrieŃi în limbajul VHDL arhitectura care utilizează microprogramarea pe orizontală (Figura
4.5). UtilizaŃi procese sau instrucŃiuni concurente de asignare a semnalelor pentru fiecare element al arhitecturii.
6.5.24. ModificaŃi descrierea arhitecturii microprogramate pentru a utiliza microprogramarea pe
verticală (Figura 4.6).

S-ar putea să vă placă și