8. instrucÞiuni secvenÞiale ªi concurente În … fosta 08.pdf · acest nume este util şi...

43
Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 1 8. 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. Do- meniul secvenţial este reprezentat de un proces sau subprogram care conţine instrucţiuni secvenţiale. Aceste in- strucţ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 10). Toate acti- vităţile descrise de acestea au loc simultan. În această lucrare se prezintă formatul şi modul de utilizare al unor instrucţiuni secvenţiale şi concu- rente. Pentru exemplificare sunt descrise unele componente combinaţionale şi secvenţiale de bază, ca de exem- plu multiplexoare, codificatoare, decodificatoare, bistabile, registre şi numărătoare. 8.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 sec- venţ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 11 î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 proce- sele 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. 8.1.1. Procese Un proces este o secvenţă de instrucţiuni care sunt executate în ordinea specificată. Declaraţia unui pro- ces delimitează un domeniu secvenţial al arhitecturii în care apare declaraţia. Procesele se utilizează pentru des- crieri funcţionale. 8.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

Upload: tranngoc

Post on 07-Feb-2018

218 views

Category:

Documents


1 download

TRANSCRIPT

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 1

8. INSTRUCŢIUNI SECVENŢIALE ŞI CONCURENTE ÎNLIMBAJUL VHDL

O descriere în limbajul VHDL are două domenii: un domeniu secvenţial şi un domeniu concurent. Do-meniul secvenţial este reprezentat de un proces sau subprogram care conţine instrucţiuni secvenţiale. Aceste in-strucţiuni sunt executate în ordinea în care apar în cadrul procesului sau subprogramului, ca şi în cazul limbajelorde programare. Domeniul concurent este reprezentat de o arhitectură, care conţine procese, apeluri concurente deproceduri, asignări concurente ale semnalelor şi instanţieri de componente (descrise în capitolul 10). Toate acti-vităţile descrise de acestea au loc simultan.

În această lucrare se prezintă formatul şi modul de utilizare al unor instrucţiuni secvenţiale şi concu-rente. Pentru exemplificare sunt descrise unele componente combinaţionale şi secvenţiale de bază, ca de exem-plu multiplexoare, codificatoare, decodificatoare, bistabile, registre şi numărătoare.

8.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 sec-venţiale. Sunt prezentate apoi instrucţiunile secvenţiale care pot apare într-un proces sau subprogram: asignareasecvenţ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 11 î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 şifuncţiilor).

• Declaraţia unui proces este prezentată în cadrul instrucţiunilor secvenţiale pentru a putea utiliza proce-sele 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.

8.1.1. Procese

Un proces este o secvenţă de instrucţiuni care sunt executate în ordinea specificată. Declaraţia unui pro-ces delimitează un domeniu secvenţial al arhitecturii în care apare declaraţia. Procesele se utilizează pentru des-crieri funcţionale.

8.1.1.1. Structura şi execuţia unui proces

Un proces poate apare oriunde în corpul unei arhitecturi (partea care începe după cuvântul cheiebegin). 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

Structura sistemelor de calcul - Lucrarea de laborator Nr. 82

end process [nume];

Declaraţia unui proces este cuprinsă între cuvintele cheie process şi end process. Unui proces i sepoate asigna în mod opţional un nume pentru identificarea mai uşoară a procesului în textul sursă. Numele esteun identificator şi trebuie urmat de caracterul ':' (cu rol de etichetă). Acest nume este util şi pentru simulare, deexemplu, pentru setarea unui punct de întrerupere a execuţiei simulării. Numele poate fi repetat la sfârşitul decla-raţ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ţiainstrucţiunilor secvenţiale din cadrul procesului, similar cu instrucţiunile dintr-un program obişnuit. Spre deose-bire de un limbaj de programare, în limbajul VHDL clauza end process nu specifică terminarea execuţiei pro-cesului. 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 asuprasemnalelor 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, pro-cesul trebuie să conţină o instrucţiune wait pentru a determina suspendarea procesului şi activarea acestuia laapariţia unui eveniment sau îndeplinirea unei condiţii. În cazul în care lista de sensibilitate este prezentă, proce-sul nu poate conţine instrucţiuni wait. Instrucţiunea wait este prezentată în secţiunea 8.1.1.3.

Partea declarativă a procesului este cuprinsă între cuvintele cheie process şi begin. În această parte sepot declara tipuri, constante, variabile şi subprograme (proceduri şi funcţii) care sunt locale procesului. Elemen-tele 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ţiu-nile care vor fi executate la fiecare activare a procesului. Nu este permisă utilizarea instrucţiunilor concurente îninteriorul unui proces.

În Exemplul 8.1 se prezintă declaraţia unui proces simplu format dintr-o singură instrucţiune de asigna-re secvenţială.

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

8.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 8.2 ca fiind identice.

Exemplul 8.2proc1: 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 desinteză vor interpreta procesul proc2 de asemenea ca o poartă ŞI cu 3 intrări, chiar dacă la simularea acestui codprocesul nu se va comporta ca atare. La simulare, o modificare a valorii semnalului a sau b va determina execu-

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 3

ţia procesului, iar valoarea funcţiei ŞI logic între semnalele a, b şi c se va asigna semnalului x. Totuşi, dacă semodifică valoarea semnalului c, procesul nu este executat, iar semnalul x nu este actualizat.

Deoarece nu este clar modul în care un sistem de sinteză ar trebui să genereze un circuit pentru care otranziţie a semnalului c nu determină o modificare a semnalului x, dar o modificare a semnalelor a sau b deter-mină actualizarea semnalului x cu valoarea funcţiei ŞI logic între semnalele a, b şi c, există următoarele alterna-tive pentru sistemele de sinteză:

• Interpretarea procesului proc2 în mod identic cu procesul proc1 (cu o listă de sensibilitate care cu-prinde toate semnalele din partea dreaptă a instrucţiunilor de asignare a semnalelor din cadrul procesu-lui);

• 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âtfuncţ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ândacestea sunt suspendate, nu se va termina niciodată (ciclul de simulare a fost descris în capitolul 6).

8.1.1.3. Instrucţiunea wait

În locul unei liste de sensibilitate, un proces poate conţine o instrucţiune wait. Utilizarea unei instrucţi-uni 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. Atuncicând se îndeplineşte condiţia specificată în cadrul instrucţiunii wait, procesul este activat şi se execută instrucţi-unile acestuia până când se întâlneşte din nou instrucţiunea wait. Limbajul VHDL permite ca un proces să conţi-nă mai multe instrucţiuni wait. Atunci când se utilizează pentru modelarea logicii combinaţionale în vedereasintezei, 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 dinExemplul 8.3, care conţine o instrucţiune wait explicită, este echivalent cu procesul din Exemplul 8.1, careconţine o listă de sensibilitate. Ambele procese se vor executa atunci când apare o modificare a valorii semnale-lor a, b sau c.

Exemplul 8.3proc3: processbegin 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ă unproces până când condiţia specificată devine adevărată datorită modificării unuia din semnalele care apar în ex-presia condiţională. Se menţionează că dacă nici un semnal din această expresie nu se modifică, procesul nu va fiactivat, chiar dacă expresia condiţională este adevărată. Exemplele următoare prezintă mai multe forme ale in-strucţiunii wait until:

Structura sistemelor de calcul - Lucrarea de laborator Nr. 84

wait until semnal = valoare;wait until semnal’event and semnal = valoare;wait until not semnal’stable and semnal = valoare;

unde semnal este numele unui semnal, iar valoare este valoarea care se testează. Dacă semnalul este de tipbit, 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 modobişnuit, semnalul testat este un semnal de ceas. De exemplu, aşteptarea frontului crescător al unui semnal deceas 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 proce-sului. Din această cauză, logica sincronă descrisă cu o instrucţiune wait until nu poate fi resetată în modasincron.

Instrucţiunea wait for permite suspendarea execuţiei unui proces pentru un timp specificat, de exem-plu:

wait for 10 ns;

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

Exemplul 8.4proc4: processbegin 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 Exemplul8.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ă simu-larea unui model. În faza de iniţializare a simulării, se execută toate procesele modelului. Dacă procesul conţineo listă de sensibilitate, toate instrucţiunile procesului vor fi executate o singură dată. În forma procesului careconţine o instrucţiune wait şi aceasta apare la sfârşit, în faza de iniţializare se execută o singură dată toate in-strucţ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, unproces cu instrucţiunea wait plasată la început nu este echivalent cu un proces care conţine o listă de sensibili-tate. Deoarece faza de iniţializare a simulării nu are echivalent hardware, nu vor exista diferenţe la sinteza celordouă 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ă. Esteposibil ca modelul care funcţionează corect la simulare să fie sintetizat într-un circuit a cărui funcţionare esteeronată.

8.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 deo-sebire dintre acestea fiind că la procesele secvenţiale semnalele de ieşire se înscriu în bistabile. Un procescombinaţional simplu este prezentat în Exemplul 8.5.

Exemplul 8.5proc5: processbegin

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 5

wait on a, b; z <= a and b;end process proc5;

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 sensibili-

tate 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 uncircuit combinaţional.

Dacă un proces nu este sensibil la toate intrările sale şi nu este un proces secvenţial, atunci nu poate fisintetizat, deoarece nu există un echivalent hardware al unui asemenea proces. Nu toate sistemele de sinteză im-pun o asemenea regulă, astfel încât trebuie acordată atenţie la scrierea proceselor combinaţionale pentru a nuintroduce erori. Asemenea erori vor avea ca efect diferenţe subtile între modelul simulat şi circuitul obţinut prinsinteză, 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 in-terpretat ca un proces secvenţial. Astfel, procesul din Exemplul 8.6 va fi interpretat ca un proces secvenţial.

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

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

Figura 8.1. Rezultatul sintezei unui proces secvenţial.

8.1.2. Instrucţiunea secvenţială de asignare a semnalelor

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

8.1.2.1. Execuţia instrucţiunii secvenţiale de asignare

Asignarea valorilor la semnale a fost prezentată pe scurt în capitolul 6. Această asignare se poate realizaprintr-o instrucţiune secvenţială sau o instrucţiune concurentă. Instrucţiunea secvenţială poate apare doar în in-teriorul unui proces, iar cea concurentă poate apare doar în exteriorul proceselor. Instrucţiunea secvenţială deasignare are o singură formă, cea simplă, care este o asignare necondiţionată. Instrucţiunea concurentă are, pelângă forma sa simplă (prezentată în secţiunea 8.2.3.1), încă două forme: asignarea condiţională (secţiunea8.2.3.2) şi asignarea selectivă (secţiunea 8.2.3.3). Instrucţiunea secvenţială de asignare are aceeaşi sintaxă cuforma 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 simboluluide 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ă cla-

Structura sistemelor de calcul - Lucrarea de laborator Nr. 86

uza after, după întârzierea specificată din acest moment. Deci, într-un proces semnalele vor fi actualizate doardupă 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. Clau-zele after sunt ignorate nu numai deoarece interpretarea lor pentru sinteză nu este specificată de standarde, ci şipentru că ar fi dificilă garantarea rezultatelor unor asemenea întârzieri. De exemplu, nu este clar dacă întârziereaar 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 încare 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 8.7 sunt echivalente.

Exemplul 8.7proc7: 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 deasignare 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ă seasigneze mai mult de o valoare la un semnal în acelaşi proces.

8.1.2.2. Reacţii inverse

O altă consecinţă a modului în care se execută asignarea semnalelor este că prin citirea unui semnalcăruia i se asignează o valoare în acelaşi proces se va obţine valoarea care i-a fost asignată semnalului la execuţiaprecedentă a procesului. Citirea unui semnal şi asignarea unei valori la acel semnal în acelaşi proces este echi-valentă cu o reacţie inversă. Într-un proces combinaţional, valoarea precedentă este o ieşire a logiciicombinaţionale, astfel încât reacţia este asincronă. Într-un proces secvenţial, valoarea precedentă este valoareamemorată într-un bistabil sau registru, astfel încât reacţia este sincronă.

În Exemplul 8.8 se prezintă un proces în care se utilizează reacţia inversă sincronă. Procesul descrie unnumărător de 4 biţi, semnalul num fiind de tip unsigned, tip care este declarat în pachetul numeric_bit. Seobservă că semnalul num este declarat în afara procesului.

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

signal num: unsigned (3 downto 0);processbegin 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 8.2.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 7

Figura 8.2. Exemplu de reacţie inversă sincronă.

8.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 pen-tru sinteza logică.

Întârzierea inerţială este implicită, fiind utilizată atunci când nu se specifică tipul întârzierii. Clauzaafter presupune în mod automat întârzierea inerţială. Într-un model cu întârziere inerţială, două modificări con-secutive ale valorii unui semnal de intrare nu vor modifica valoarea unui semnal de ieşire dacă timpul dintreaceste 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 vorrămâne neschimbate.

Figura 8.3. Ilustrarea întârzierii inerţiale.

Figura 8.3 ilustrează întârzierea inerţială cu ajutorul unui buffer simplu. Bufferul cu o întârziere de 20ns 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 mo-mentul 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 8.3 poate fi modelat prin următoarea instrucţiune de asignare:b <= a after 20 ns;

8.1.2.4. Întârzierea de transport

Întârzierea de transport trebuie indicată în mod explicit prin cuvântul cheie transport. Aceasta repre-zintă întârzierea unei conexiuni, în care efectul apariţiei unui impuls al unui semnal de intrare este propagat laieşire cu întârzierea specificată, indiferent de durata acestui impuls. Întârzierea de transport este utilă în specialpentru modelarea liniilor de transmisie şi a conexiunilor dintre componente.

Considerând acelaşi buffer din Figura 8.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 8.4. Impulsul semnalului deintrare este propagat nemodificat la ieşire cu o întârziere de 20 ns.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 88

Figura 8.4. Ilustrarea întârzierii de transport.

Dacă se utilizează întârzierea de transport, bufferul din Figura 8.4 poate fi modelat prin următoarea in-strucţiune de asignare:

b <= transport a after 20 ns;

8.1.3. Variabile

Restricţiile impuse asupra semnalelor reduc posibilităţile de utilizare ale acestora. Deoarece semnalelepot păstra numai ultima valoare asignată, ele nu pot fi utilizate pentru memorarea rezultatelor intermediare sautemporare în cadrul unui proces. Un alt inconvenient este că noile valori sunt asignate semnalelor nu în momen-tul execuţiei instrucţiunii de asignare, ci după suspendarea execuţiei procesului. Aceasta determină ca analizaunei descrieri să fie dificilă.

Spre deosebire de semnale, variabilele pot fi declarate în interiorul unui proces şi se pot utiliza pentrumemorarea rezultatelor intermediare. Variabilele pot fi utilizate însă numai în domeniul secvenţial al limbajuluiVHDL, deci în interiorul proceselor sau subprogramelor, şi nu pot fi declarate sau utilizate direct într-o arhitectu-ră. Ele sunt deci locale procesului sau subprogramului respectiv.

8.1.3.1. Declararea şi iniţializarea variabilelor

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

Exemplul 8.9variable 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 maidin stânga a tipului. De exemplu, pentru tipul bit valoarea iniţială implicită este '0', iar pentru tipul integeraceastă 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 - Lucrarea de laborator Nr. 8 9

8.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ă valoarespecificată de o expresie. Expresia poate conţine variabile, semnale şi literale. Variabila şi rezultatul evaluăriiexpresiei 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 deosebi-re 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 actuali-zarea se execută numai la suspendarea procesului, în timp ce pentru asignarea variabilelor nu se planifi-că un eveniment, iar actualizarea se execută instantaneu.

• La asignarea semnalelor se poate specifica o întârziere, în timp ce asignarea variabilelor nu poate fi în-târziată.

• Într-un proces, doar ultima asignare a unei valori la un semnal este efectivă. În schimb, pot exista nume-roase asignări la o variabilă în acelaşi proces, toate fiind efective.

Exemplul 8.10 ilustrează utilizarea variabilelor pentru memorarea rezultatelor intermediare.

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

architecture functional of add_1 isbegin 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 sumatorelementar, dar ilustrează utilizarea variabilelor. Rezultatul se generează prin crearea a două semisumatoare, pri-mul 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.

8.1.4. Instrucţiunea if

8.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 devaloarea 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;

Structura sistemelor de calcul - Lucrarea de laborator Nr. 810

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

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

8.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ţiuniiif fără nici o ramură elsif. Exemplul 8.12 prezintă utilizarea unei asemenea instrucţiuni pentru descrierea unuicomparator.

Exemplul 8.12library 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 isbegin 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 8.5. De notat că, lafel 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 8.5. Implementarea unei instrucţiuni if.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 11

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

Exemplul 8.13process (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 8.6. Acest cir-cuit este echivalent cu cel rezultat prin implementarea unei instrucţiuni de asignare condiţională. Aceasta este oinstrucţiune concurentă şi va fi prezentată în secţiunea 8.2.3.2.

Figura 8.6. Implementarea unei instrucţiuni if cu ramuri multiple.

Condiţiile din ramurile succesive ale unei instrucţiuni if sunt evaluate independent. În exemplul anteri-or, condiţiile implică cele două semnale s0 şi s1. Pot exista oricâte condiţii, fiecare din acestea fiind indepen-dentă de celelalte. Structura instrucţiunii if asigură faptul că primele condiţii vor fi testate înaintea celorlalte. Înacest 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 sem-nalul s1.

Este important să se reţină existenţa acestei priorităţi cu care se testează condiţiile, astfel încât să fieeliminate condiţiile redundante. Considerăm instrucţiunea if din Exemplul 8.14, care este echivalentă cu in-strucţiunea if din Exemplul 8.13.

Exemplul 8.14process (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 ainstrucţiunii if este falsă. Se recomandă evitarea unor asemenea redundanţe, deoarece nu există garanţia că elevor 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 sem-nale şi variabile diferite. Dacă fiecare ramură este dependentă de acelaşi semnal, atunci este mai avantajos să seutilizeze o instrucţiune case. Instrucţiunea case este prezentată în secţiunea 8.1.5.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 812

8.1.4.3. Instrucţiuni if incomplete

În exemplele prezentate până acum, toate instrucţiunile if au fost complete. Cu alte cuvinte, semnaluluidestinaţie i s-a asignat o valoare în toate condiţiile posibile. Sunt posibile însă două situaţii în care unui semnalnu i se asignează o valoare: atunci când lipseşte clauza else a instrucţiunii if sau atunci când unui semnal nu ise asignează o valoare într-o ramură a instrucţiunii if. În ambele cazuri, interpretarea este aceeaşi. În situaţiile încare 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ţiiinverse în cadrul circuitului.

Primul caz este ilustrat prin Exemplul 8.15.

Exemplul 8.15process (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, sem-nalul z primeşte o valoare în cazul în care condiţia enable = '1' este adevărată, dar rămâne la valoarea prece-dentă î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 8.15 este echivalentă cu instrucţiunea if din exemplul următor.

Exemplul 8.16process (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, vaexista o reacţie inversă de la ieşirea circuitului la intrare. Aceasta deoarece valoarea semnalului de la execuţiaprecedentă 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 intra-re de validare, ca în Exemplul 8.17.

Exemplul 8.17processbegin 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ă, darnu este actualizat în cazul în care condiţia este falsă. În acest caz, valoarea precedentă a semnalului q este păs-trată prin reacţia inversă secvenţială a semnalului q. Circuitul rezultat este prezentat în Figura 8.7.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 13

Figura 8.7. Implementarea unei instrucţiuni if incomplete.

Instrucţiunea if din Exemplul 8.17 este echivalentă cu instrucţiunea if completă din exemplul urmă-tor.

Exemplul 8.18processbegin 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 esteechivalent cu păstrarea valorii sale anterioare.

Una din cele mai obişnuite erori întâlnite în descrierile VHDL destinate sintezei logice este introducereaneintenţionată a reacţiei inverse în circuit datorită unei instrucţiuni if incomplete. Pentru a evita introducereareacţ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. Înpractică, există două posibilităţi pentru aceasta: asignarea unei valori unui semnal de ieşire în fiecare ramură ainstrucţiunii if şi includerea clauzei else, sau iniţializarea semnalului printr-o instrucţiune de asignare necon-diţionată înaintea instrucţiunii if.

În exemplul următor, deşi instrucţiunea if pare completă, în cele două ramuri ale instrucţiuniiasignările se efectuează la semnale diferite. De aceea, ambele semnale z şi y vor avea o reacţie inversă asincro-nă.

Exemplul 8.19processbegin 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 8.20).

Exemplul 8.20processbegin wait on a, b, c; if c = '1' then z <= a; elsif c = '0' then z <= b; end if;end process;

Structura sistemelor de calcul - Lucrarea de laborator Nr. 814

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

Figura 8.8. Implementarea unei instrucţiuni if cu o condiţie redundantă.

8.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 utili-zării variabilelor, cu o singură diferenţă. Ca şi în cazul unui semnal, dacă unei variabile i se asignează valori nu-mai în anumite ramuri ale instrucţiunii if, se păstrează valoarea anterioară a variabilei prin reacţie inversă. Spredeosebire de cazul utilizării unui semnal, citirea şi scrierea unei variabile în acelaşi proces va determina o reacţieinversă numai dacă citirea apare înaintea scrierii. În acest caz, valoarea citită este valoarea precedentă a variabi-lei. Î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. Reamintimcă un proces secvenţial este interpretat la sinteză prin plasarea unui bistabil sau registru înaintea ieşirii fiecăruisemnal căruia i s-a asignat o valoare în procesul respectiv. Aceasta înseamnă că în mod normal variabilele nusunt î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 8.21 se descrie un numărător utilizând tipul întreg unsigned. La incrementarea unei va-lori de tip unsigned, dacă valoarea este cea maximă a domeniului se obţine valoarea minimă a domeniului.

Exemplul 8.21process 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 pen-tru 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, deoarecetoate semnalele cărora li se asignează o valoare într-un proces secvenţial vor fi înscrise în registre. Acest registrusuplimentar va conţine întotdeauna aceeaşi valoare ca şi registrul variabilei num. Sistemul de sinteză va eliminaîn mod normal acest registru redundant.

8.1.5. Instrucţiunea case

Ca şi instrucţiunea if, instrucţiunea case selectează pentru execuţie una din mai multe secvenţe alter-native de instrucţiuni pe baza valorii unei expresii. Spre deosebire de instrucţiunea if, în cazul instrucţiunii ca-se expresia nu trebuie să fie booleană, ci poate fi reprezentată de un semnal, o variabilă sau o expresie de orice

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 15

tip discret (un tip enumerat sau întreg) sau un tablou unidimensional de caractere (inclusiv bit_vector saustd_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 identifica-rea 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. Încazul în care expresia este egală cu valoarea individuală sau cu una din valorile setului, se execută secvenţa deinstrucţ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 întrecuvintele cheie begin şi end. Clauza others se poate utiliza pentru a specifica execuţia unei secvenţe de in-strucţ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 individualedin 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ţiuniend case;

Observaţii• Într-o instrucţiune case trebuie enumerate toate valorile posibile pe care le poate avea expresia de se-

lecţie, ţinând cont de tipul sau subtipul acesteia. De exemplu, dacă expresia de selecţie este de tipstd_logic_vector de 2 biţi, trebuie enumerate 81 de valori, deoarece pentru un singur bit pot exista9 valori posibile. Dacă nu sunt enumerate toate valorile, trebuie utilizată clauza others.

• Clauza others trebuie să fie ultima dintre toate opţiunile.

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

Exemplul 8.22type 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;

Structura sistemelor de calcul - Lucrarea de laborator Nr. 816

Exemplul 8.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 8.23library 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 isbegin 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. Deosebireaeste că toate opţiunile depind de aceeaşi intrare şi sunt mutual exclusive. Aceasta permite anumite optimizări alecondiţiilor de control comparativ cu o instrucţiune if cu ramuri multiple, la care nu se va presupune nici o de-pendenţă între diferitele condiţii.

8.1.6. Instrucţiuni de buclare

Instrucţiunile de buclare permit execuţia repetată a unei secvenţe de instrucţiuni, de exemplu, prelucra-rea 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 debuclare 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 cazulinstrucţ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.

8.1.6.1. Instrucţiunea loop

Instrucţiunea de buclare simplă loop are sintaxa următoare:[etichetă:] loop secvenţă_de_instrucţiuniend loop [etichetă];

Instrucţiunea are o etichetă opţională, care poate fi utilizată pentru identificarea instrucţiunii. Instrucţiu-nea loop are ca efect repetarea instrucţiunilor din corpul buclei de un număr nelimitat de ori. În cazul acesteiinstrucţiuni, singura posibilitate de terminare a execuţiei este utilizarea unei instrucţiuni exit (prezentată în sec-ţiunea 8.1.6.5).

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 17

8.1.6.2. Instrucţiunea while loop

Instrucţiunea while loop este o instrucţiune de buclare condiţionată. Sintaxa acestei instrucţiuni esteurmătoarea:

[etichetă:] while condiţie loop secvenţă_de_instrucţiuniend 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 bucleise termină atunci când condiţia testată devine falsă, caz în care se execută instrucţiunea care urmează după clau-za end loop.

Exemplul 8.24process 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 8.24 se numără fronturile crescătoare ale semnalului de ceas clk atât timp câtsemnalul nivel are valoarea '1'. Stabilitatea semnalului nivel nu este testată. Se testează doar dacă acest sem-nal are valoarea '1' la detectarea unui front crescător al semnalului clk, şi nu se testează dacă valoarea semnalu-lui nivel s-a modificat de la testarea anterioară.

Instrucţiunile de buclare pot fi imbricate pe mai multe nivele. Deci, corpul buclei unei instrucţiuniwhile loop poate conţine o altă instrucţiune de buclare, în particular o instrucţiune while loop, după cum searată în exemplul următor.E1: while i < 10 loopE2: while j < 20 loop

... end loop E2;end loop E1;

8.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 utilizainstrucţiunea for loop. Sintaxa acestei instrucţiuni este următoarea:

[etichetă:] for contor in domeniu loop secvenţă_de_instrucţiuniend loop [etichetă];

Într-o instrucţiune for loop se specifică un contor de iteraţii şi un domeniu. Instrucţiunile din corpulbuclei sunt executate cât timp contorul se află în domeniul specificat. După terminarea unei iteraţii, contorului ise asignează următoarea valoare din domeniu. Domeniul poate fi unul crescător, specificat prin cuvântul cheieto, sau descrescător, specificat prin cuvântul cheie downto. Acest domeniu poate fi specificat şi sub forma unuitip enumerat sau subtip, caz în care nu se specifică în mod explicit limitele domeniului în cadrul instrucţiuniifor loop. Limitele domeniului vor fi determinate de compilator din declaraţia tipului sau subtipului respectiv.

Instrucţiunea for loop din Exemplul 8.25 calculează pătratele valorilor întregi cuprinse între 1 şi 10,pe care le depune în tabloul i_patrat.

Exemplul 8.25for i in 1 to 10 loop i_patrat (i) <= i * i;end loop;

Structura sistemelor de calcul - Lucrarea de laborator Nr. 818

Contorul de iteraţii din acest exemplu este în mod implicit de tip integer, deoarece tipul acestuia nu afost definit în mod explicit. Forma completă a declaraţiei domeniului pentru contorul de iteraţii este similară cucea 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 (înexemplul anterior, i) pentru a-i modifica valoarea. Limbajul VHDL nu permite însă asignarea unei valori conto-rului de iteraţii sau utilizarea acestuia ca parametru de intrare sau de ieşire al unei proceduri. Contorul poate fiutilizat însă într-o expresie, cu condiţia să nu i se modifice valoarea. Un alt aspect legat de contorul de iteraţiieste că acesta nu trebuie declarat în mod explicit în cadrul procesului. Acest contor este declarat în mod implicitca 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 des-cris de conţinutul instrucţiunii la fiecare iteraţie a buclei. Utilizarea instrucţiunii for loop pentru generarea unuicircuit este ilustrată în Exemplul 8.26.

Exemplul 8.26entity 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 isbegin 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ţiide 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ă conexiu-ne î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-oiteraţie a buclei, valoare care este citită apoi într-o altă iteraţie. De obicei, este necesară iniţializarea unei aseme-nea variabile înaintea intrării în buclă. Exemplul 8.27 prezintă un asemenea circuit.

Exemplul 8.27library 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 - Lucrarea de laborator Nr. 8 19

architecture functional of contorizare_unu isbegin 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ă apoisemnalului de ieşire num la sfârşitul procesului. Corpul buclei – o instrucţiune if conţinând o asignare a uneivariabile – reprezintă un bloc format dintr-un multiplexor şi un sumator, care va fi generat la sinteză pentru fie-care iteraţie a buclei. Ieşirea unui bloc devine intrarea rez a următorului bloc. Figura 8.9 prezintă circuitul gene-rat.

Figura 8.9. Implementarea unei instrucţiuni for loop.

În Exemplul 8.27, domeniul contorului de iteraţii al instrucţiunii for loop a fost specificat în mod ex-plicit ca fiind 15 downto 0. În practică, această specificare explicită este utilizată foarte rar pentru accesareatablourilor, fiind recomandată utilizarea atributelor pentru tablouri. Există patru posibilităţi, în funcţie de dome-niul 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ătorsau 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 'rever-se_range:for i in v'reverse_range loop

3. Dacă elementele unui tablou trebuie parcurse de la indexul minim la cel maxim, indiferent de domeniulcrescă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 detip tablou va avea un domeniu crescător sau descrescător, devine foarte importantă alegerea limitelor corectepentru instrucţiunile de buclare. Această problemă va fi prezentată mai detaliat în capitolul 11. Pentru tipuriletablou 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ă bitulc.m.p.s., indiferent de domeniul tabloului. Aceasta înseamnă că modul corect pentru accesul acestor tablouri esteutilizarea atributului 'range sau 'reverse_range.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 820

Astfel, pentru accesul unui tablou n reprezentând o valoare întreagă începând de la bitul c.m.s. sprebitul 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 're-verse_range:

for i in n'reverse_range loop

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

8.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ă şitrecerea la următoarea iteraţie. Pentru aceasta se poate utiliza instrucţiunea next. Sintaxa acestei instrucţiuni esteurmă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ă şicontrolul este transferat la începutul instrucţiunii de buclare, fie necondiţionat, dacă clauza when nu este prezen-tă, fie condiţionat, dacă această clauză este prezentă. Contorul de iteraţii va fi actualizat, iar dacă limita domeni-ului nu a fost atinsă, execuţia va continua cu prima instrucţiune din corpul buclei. În caz contrar, execuţiainstrucţ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ă), încadrul instrucţiunii next se poate specifica o etichetă, aceasta fiind eticheta instrucţiunii de buclare de nivelimediat superior în care este cuprinsă instrucţiunea next. Această etichetă are doar rolul de a creşte claritateadescrierii ş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 unuigrup de instrucţiuni. Pentru sinteza instrucţiunii next sunt necesare aceleaşi circuite ca şi cele necesare pentrusinteza 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 8.28 prezintă descrierea modificată a acestui circuit. În locul instrucţiunii if se utilizează o instrucţiu-ne next, prin care se abandonează o iteraţie în cazul în care valoarea elementului curent este '0', astfel că nu seexecută incrementarea contorului.

Exemplul 8.28library 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 isbegin 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 - Lucrarea de laborator Nr. 8 21

Figura 8.10. Implementarea unei instrucţiuni for loop care conţine o instrucţiune next.

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

8.1.6.5. Instrucţiunea exit

Există situaţii în care execuţia unei instrucţiuni de buclare trebuie oprită complet, fie datorită apariţieiunei erori în timpul execuţiei unui model, fie datorită faptului că prelucrarea trebuie terminată înaintea depăşiriidomeniului de către contorul de iteraţii. În asemenea situaţii, se poate utiliza instrucţiunea exit. Sintaxa acesteiinstrucţ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 spe-cificată printr-o clauză when. În acest caz, se va opri în mod necondiţionat execuţia instrucţiunii curente de bu-clare. În cazul în care instrucţiunea exit apare într-o instrucţiune de buclare aflată în interiorul unei alteinstrucţiuni de buclare, va fi oprită doar execuţia instrucţiunii interioare de buclare, dar execuţia instrucţiuniiexterioare de buclare va continua.

Dacă în instrucţiunea exit se specifică o etichetă a unei instrucţiuni de buclare, la întâlnirea instrucţiu-nii 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 încazul în care condiţia specificată de această clauză este adevărată. Următoarea instrucţiune executată depinde deprezenţa sau absenţa unei etichete în cadrul instrucţiunii. Dacă se specifică o etichetă a unei instrucţiuni de bu-clare, următoarea instrucţiune executată va fi prima din instrucţiunea de buclare specificată de acea etichetă. Da-că nu se specifică o etichetă, următoarea instrucţiune executată va fi cea de după clauza end loop a instrucţiuniide buclare curente.

Instrucţiunea exit se poate utiliza pentru a termina execuţia unei instrucţiuni loop simple, după cumse arată în Exemplul 8.30.

Exemplul 8.30E3: loop

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

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

Exemplul 8.31library 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 isbegin

Structura sistemelor de calcul - Lucrarea de laborator Nr. 822

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 8.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 8.11. Instrucţiu-nea 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ţiuniiexit devine adevărată. Se poate observa că implementarea unei instrucţiuni exit dintr-o buclă este similară cucea a unei instrucţiuni if dintr-o buclă.

8.1.7. Instrucţiunea secvenţială assert

Instrucţiunea assert este utilă pentru afişarea unor mesaje de avertisment sau de eroare în timpul si-mulării unui model. Această instrucţiune testează valoarea unei condiţii booleene şi afişează mesajul specificat încazul î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ă va-loare este TRUE, instrucţiunea nu are nici un efect. Dacă valoarea este FALSE, se afişează textul specificat în cla-uza 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 "Assertionviolation".

Clauza opţională severity permite specificarea nivelului de severitate al violării aserţiunii. Nivelul deseveritate trebuie să fie o expresie cu tipul predefinit severity_level. Acest tip (care a fost descris în capito-lul 7) conţine următoarele valori, în ordinea crescătoare a nivelului de severitate: note, warning, error şifailure. Dacă această clauză este omisă, se va presupune nivelul de severitate implicit error. Utilizarea ni-velelor 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 carezultatele să fie imprevizibile.

• Nivelul error se utilizează atunci când violarea aserţiunii reprezintă o eroare care determină funcţiona-rea incorectă a modelului, în acest caz execuţia simulării fiind oprită.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 23

• Nivelul failure se utilizează atunci când violarea aserţiunii reprezintă o eroare fatală, cum este îm-pă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 8.32assert 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 fioprită.

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 iden-tic cu versiunea secvenţială, dar poate apare numai în afara unui proces sau subprogram.

• De obicei, sistemele de sinteză ignoră instrucţiunea assert.

8.2. Instrucţiuni concurenteOperaţ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 fispecificat sub forma unui proces separat, iar comunicaţia dintre procese se poate realiza prin semnale. Comple-xitatea diferitelor procese poate fi foarte variată, de la o simplă poartă logică până la un procesor. Modelareasistemelor 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 prin-cipalele instrucţiuni concurente ale limbajului VHDL. Cea mai importantă instrucţiune concurentă este declaraţiaunui proces. Procesele au fost prezentate în secţiunea 8.1.1, astfel încât în secţiunea de faţă vor fi prezentate doarprincipalele caracteristici ale proceselor. Alte instrucţiuni concurente sunt instrucţiunea concurentă de asignare asemnalelor, instrucţiunea block, instrucţiunea concurentă assert, instrucţiunea concurentă de apel a unei pro-ceduri, instanţierea unei componente şi instrucţiunea generate. Instrucţiunea de apel a procedurilor va fi pre-zentată în capitolul 11 în care se descriu subprogramele. Instanţierea unei componente şi instrucţiuneagenerate vor fi descrise în capitolul 10 dedicat proiectării structurale.

8.2.1. Structura şi execuţia unei arhitecturi

După cum s-a arătat în capitolul 6, definiţia unei arhitecturi are două părţi: o parte declarativă şi o partedescriptivă. În partea declarativă se pot declara obiecte care sunt interne arhitecturii. Partea descriptivă conţineinstrucţiuni concurente. Acestea definesc procesele sau blocurile interconectate care descriu funcţionarea saustructura globală a sistemului.

Toate procesele dintr-o arhitectură se execută în paralel unele faţă de altele, dar instrucţiunile din cadrulunui anumit proces se execută secvenţial. Un proces suspendat este activat din nou atunci când unul din semna-lele din lista sa de sensibilitate îşi modifică valoarea. Atunci când există mai multe procese într-o arhitectură, lamodificarea 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 alteprocese.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 824

Figura 8.12. Schema unui sumator de 1 bit.

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

Exemplul 8.33entity 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. Acestease pot utiliza atât pentru activarea proceselor, cât şi pentru sincronizarea între procese. Astfel, un semnal poateaştepta un eveniment asupra unui semnal de intrare, semnal care este asignat într-un alt proces. Acest semnal estedeclarat în partea declarativă a arhitecturii, şi astfel este vizibil pentru toate procesele din cadrul arhitecturii.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 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.

8.2.2. Procese

Procesele sunt compuse din instrucţiuni secvenţiale, dar declaraţiile proceselor reprezintă instrucţiuniconcurente. Declaraţia unui proces a fost prezentată în secţiunea 8.1.1.1. Se pot formula următoarele caracteris-tici 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 entitateacu care este asociată arhitectura.

8.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ândacea instrucţiune. O asemenea instrucţiune este executată în paralel cu alte instrucţiuni concurente sau alte pro-cese. 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 continua-re.

8.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 driverpentru semnalul asignat. Deosebirea faţă de versiunea secvenţială este că instrucţiunea concurentă de asignareapare î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ţi-ală de asignare.

Descrierea sumatorului de 1 bit din Exemplul 8.33 poate fi simplificată prin utilizarea instrucţiunilorconcurente de asignare, după cum se arată în Exemplul 8.34.

Exemplul 8.34entity 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;

Structura sistemelor de calcul - Lucrarea de laborator Nr. 826

După cum se observă din exemplul anterior, instrucţiunile concurente de asignare apar direct în cadrularhitecturii, şi nu în interiorul unui proces. Ordinea în care sunt scrise instrucţiunile nu are importanţă. La simu-lare 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 dinlista de sensibilitate a acestora sau de întâlnirea unei instrucţiuni wait. În cazul instrucţiunilor concurente deasignare, modificarea valorii unuia din semnalele care apar în partea dreaptă a asignării activează execuţia asig-nării, fără să se specifice în mod explicit o listă de sensibilitate. Activarea unei instrucţiuni de asignare este inde-pendentă de activarea altor instrucţiuni concurente din cadrul arhitecturii.

Instrucţiunile concurente de asignare se utilizează pentru descrieri de tipul fluxului de date. Prin sintezaacestor 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ă saudefinită 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 dintreacestea.

8.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 acărei condiţie booleană asociată este adevărată. La execuţia unei instrucţiuni de asignare condiţională, condiţiilesunt 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 dintreacestea.

Deosebirile dintre instrucţiunea de asignare condiţională şi instrucţiunea condiţională if sunt următoa-rele:

• Instrucţiunea de asignare condiţională este o instrucţiune concurentă, deci poate fi utilizată într-o arhi-tectură, în timp ce instrucţiunea if este secvenţială, astfel că poate fi utilizată numai în interiorul unuiproces.

• Instrucţiunea de asignare condiţională poate fi utilizată numai pentru asignarea valorii unor semnale, întimp ce instrucţiunea if poate fi utilizată pentru execuţia oricărei instrucţiuni secvenţiale.

Exemplul 8.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 echi-valentă.

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

architecture arh1_xor2 of xor2 isbegin x <= '0' when a = b else '1';end arh1_xor2;

architecture arh2_xor2 of xor2 isbegin process (a, b)

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 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 dinexpresiile sursă. Figura 8.13 prezintă circuitul rezultat pentru următoarea instrucţiune:

s <= a xor b when c = '1' else not (a xor b);

Circuitul din Figura 8.13 este cel generat iniţial de sistemul de sinteză, dar operatorul de egalitate va fiminimizat 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 careexistă 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 8.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 acărei condiţie este adevărată. Aceasta echivalează din punct de vedere hardware cu o serie de multiplexoare cudouă căi, prima condiţie controlând multiplexorul cel mai apropiat de ieşire. Circuitul rezultat pentru acestexemplu este prezentat în Figura 8.14. Pentru acest circuit, condiţiile au fost deja optimizate, astfel încât semna-lele 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 in-trările b şi c.

Figura 8.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 multiple-xoare. De acest aspect trebuie să se ţină cont la proiectare: cu cât o expresie sursă apare mai târziu în lista deselecţie, cu atât semnalele din această expresie vor traversa mai multe multiplexoare în circuitul rezultat la sinte-ză.

La implementare, se consideră că fiecare condiţie dintr-o instrucţiune de asignare condiţională este in-dependentă de celelalte. Aceasta înseamnă că, în cazul în care condiţiile sunt dependente (de exemplu, se bazea-ză 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 selpoate fi numai '0'. De aceea, a doua condiţie este redundantă, iar ultima ramură else nu poate fi atinsă. La sinte-

Structura sistemelor de calcul - Lucrarea de laborator Nr. 828

ză, această instrucţiune de asignare condiţională va fi implementată totuşi prin două multiplexoare, după cum seilustrează în Figura 8.15.

Figura 8.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ă eliminemultiplexorul redundant, dar în cazul unor exemple mai complexe această eliminare nu poate fi garantată. Moti-vul pentru care nu se obţine o implementare optimizată este că, în cazul general, detectarea unui cod VHDL lacare 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ţi-uni de asignare selectivă.

8.2.3.3. Instrucţiunea de asignare selectivă

Ca şi instrucţiunea de asignare condiţională, instrucţiunea de asignare selectivă permite selectarea uneiexpresii sursă pe baza unei condiţii. Deosebirea constă în faptul că instrucţiunea de asignare selectivă utilizează osingură condiţie pentru selecţia dintre diferite opţiuni. Această instrucţiune este echivalentă funcţional cu in-strucţ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 celeale căror opţiuni includ valoarea expresiei de selecţie. Sintaxa opţiunilor este aceeaşi ca şi în cazul instrucţiuniicase. Astfel, fiecare opţiune poate fi reprezentată de o valoare individuală sau de un set de valori. În cazul încare o opţiune este reprezentată de un set de valori, se pot specifica fie valorile individuale din set, separate prinsimbolul “|”, 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ţiunepoate 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 acoperitede setul de opţiuni.

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

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

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

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 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", x <= '1' when "01", x <= '1' when "10", x <= '0' when "11";end arh_xor2;

8.2.3.4. Instrucţiunea block

O instrucţiune block defineşte un grup de instrucţiuni concurente. Această instrucţiune este utilă pentruorganizarea 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_concurenteend block [etichetă];

Eticheta obligatorie denumeşte blocul. În partea de declaraţii se pot declara obiecte locale blocului. De-claraţ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 8.37 ilustrează utilizarea blocurilor pe mai multe nivele ierarhice.

Exemplul 8.37B1: block signal s: bit; -- declaraţia "s" în blocul B1begin 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 B1end block B1;

Introducerea blocurilor în cadrul unei descrieri nu afectează execuţia unui model la simulare, ci are doarrol de organizare a descrierii.

La declararea unui bloc se poate specifica o expresie booleană, numită expresie de gardă. Această ex-presie, specificată în paranteze după cuvântul cheie block, crează în mod implicit un semnal boolean numit gu-ard, care se poate utiliza pentru controlul unor operaţii din cadrul blocului. Acest semnal poate fi citit ca orice

Structura sistemelor de calcul - Lucrarea de laborator Nr. 830

alt semnal din cadrul instrucţiunii block, dar nu poate fi actualizat printr-o instrucţiune de asignare. De fiecaredată când apare o tranzacţie asupra unuia din semnalele dintr-o expresie de gardă, expresia este evaluată şi sem-nalul 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ţiuniiblock. Avantajul acestei declarări explicite este că se poate utiliza un algoritm mai complex pentru controlulsemnalului guard decât cel permis de o expresie booleană. În particular, se poate utiliza un proces separat pen-tru controlul acestui semnal.

Dacă într-un bloc nu se specifică o expresie de gardă şi semnalul guard nu este declarat în mod expli-cit, atunci acest semnal are întotdeauna valoarea TRUE.

Semnalul guard poate fi utilizat pentru controlul instrucţiunilor de asignare a semnalelor din cadrulblocului. O asemenea instrucţiune de asignare conţine cuvântul cheie guarded după simbolul de asignare, caredetermină 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ă arevaloarea TRUE.

În Exemplul 8.38, semnalului out1 i se va asigna valoarea not in1 numai dacă valoarea expresieiclk'event and clk = '1' va fi adevărată.

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

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

Exemplul 8.39UAL: 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 poateutiliza 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 me-canism mai puternic pentru partiţionare, şi anume instanţierea componentelor. Această instanţiere va fiprezentată în capitolul 10.

8.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 - Lucrarea de laborator Nr. 8 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 cadrulexpresiei condiţionale, spre deosebire de instrucţiunea secvenţială assert, care se va executa atunci când seajunge la această instrucţiune în cadrul unui proces sau subprogram.

8.3. Descrierea unor circuite combinaţionale

8.3.1. Multiplexoare

Pentru descrierea multiplexoarelor se pot utiliza diferite metode. Exemplul 8.40 prezintă descriereamultiplexorului 4:1 pentru magistrale de 4 biţi din Figura 8.16 utilizând o instrucţiune de asignare selectivă.

Figura 8.16. Schema unui multiplexor 4:1 pentru magistrale de 4 biţi.

Exemplul 8.40library 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 isbegin 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 tipstd_logic_vector şi există nouă valori posibile ale unui obiect de acest tip. Toate valorile posibile ale sem-nalului de selecţie trebuie acoperite. În cazul în care nu s-ar fi utilizat opţiunea others, doar patru din cele 81 devalori 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 aveaalte 77 de valori posibile. Se poate utiliza şi valoarea metalogică "--" pentru asignarea unei valori indiferentesemnalului x.

Multiplexorul 4:1 poate fi descris cu ajutorul unei instrucţiuni if în modul arătat în Exemplul 8.41.

Exemplul 8.41architecture arh_mux of mux isbeginmux4_1: process (a, b, c, d, s) begin if s = "00" then x <= a;

Structura sistemelor de calcul - Lucrarea de laborator Nr. 832

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 seobţ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 suntmutual exclusive. Utilizarea unei instrucţiuni if în aceste cazuri poate determina generarea unei logici supli-mentare pentru a asigura faptul că precedentele condiţii nu sunt adevărate. În locul unei instrucţiuni if, este maiavantajoasă utilizarea unei ecuaţii booleene sau a unei instrucţiuni case.

8.3.2. Codificatoare prioritare

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

Figura 8.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 8.42.

Exemplul 8.42library 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 isbegin 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ă valoareasemnalului w atunci când a este '1', chiar dacă b, c sau d sunt '1'. Semnalul b este prioritar faţă de semnalele c şid, 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 - Lucrarea de laborator Nr. 8 33

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

Exemplul 8.43library 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 isbegin 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 8.43 necesită porţi ŞI cu doar două intrări. Deşi încazul circuitelor CPLD (Complex Programmable Logic Device) porţile ŞI cu un număr mai mare de intrări nunecesită, de obicei, resurse suplimentare, în cazul circuitelor FPGA (Field-Programmable Gate Array) acesteporţi pot necesita celule logice şi nivele logice suplimentare. Descrierile din Exemplul 8.42 şi Exemplul 8.43 nusunt echivalente funcţional, această echivalenţă existând doar în cazul în care semnalele a, b, c şi d sunt mutualexclusive. În acest caz, descrierea din Exemplul 8.43 generează o logică echivalentă cu un număr mai redus deresurse.

8.4. Descrierea unor circuite secvenţiale

8.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 acestorcircuite. Semnalele generate la ieşirile unui circuit secvenţial depind atât de semnalele de intrare, cât şi de stareacircuitului.

Starea prezentă a circuitului este determinată de o stare anterioară şi de valorile semnalelor de intrare. Încazul circuitelor secvenţiale sincrone, modificarea stării se poate realiza la momente bine definite de timp subcontrolul unui semnal de ceas. În cazul circuitelor secvenţiale asincrone, modificarea stării poate fi cauzată deschimbarea aleatoare în timp a valorii unui semnal de intrare. Comportamentul unui circuit asincron este în gene-ral mai puţin sigur, evoluţia stării fiind influenţată şi de timpii de întârziere ai componentelor circuitului. Trece-rea î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 dememorare ale unui circuit sincron îşi modifică simultan starea, ceea ce elimină apariţia unor stări intermediareinstabile. Prin testarea semnalelor de intrare la momente bine definite de timp se reduce influenţa întârzierilor şia eventualelor zgomote.

Există două tehnici de proiectare a circuitelor secvenţiale: Mealy şi Moore. În cazul circuitelor secvenţi-ale Mealy, semnalele de ieşire depind atât de starea curentă, cât şi de intrările prezente. În cazul circuitelor sec-venţiale Moore, ieşirile sunt dependente numai de starea curentă, fără să depindă în mod direct de intrări. MetodaMealy 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. Proiectareaprin metoda Moore necesită mai multe elemente de memorare pentru acelaşi tip de comportament, dar funcţiona-rea circuitului este mai sigură.

8.4.2. Bistabile

În Exemplul 8.44 se descrie un bistabil sincron de tip D acţionat pe frontul crescător al semnalului deceas (Figura 8.18).

Structura sistemelor de calcul - Lucrarea de laborator Nr. 834

Figura 8.18. Simbolul unui bistabil de tip D.

Exemplul 8.44library 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 isbegin 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 ceasclk. Tranziţia semnalului de intrare d nu determină activarea procesului. Expresia clk'event şi lista de sensi-bilitate 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 des-crierea evenimentelor acţionate pe frontul semnalului de ceas.

Pentru descrierea unui circuit latch acţionat pe nivel (Figura 8.19), se elimină condiţia clk'event şi seinserează intrarea de date d în lista de sensibilitate a procesului, după cum se arată în Exemplul 8.45.

Figura 8.19. Simbolul unui circuit latch de tip D.

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

În exemplele 8.44 şi 8.45 nu există o condiţie else. Fără această condiţie, este specificat în mod impli-cit 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 - Lucrarea de laborator Nr. 8 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 sistemede sinteză nu permit utilizarea unei expresii else după condiţia if (clk'event and clk = '1'), deoareceimplementarea unei asemenea descrieri poate fi ambiguă.

După cum s-a arătat în secţiunea 8.1.4.3, în cazul în care o instrucţiune condiţională nu are toate alter-nativele specificate, la sinteză se generează un element de memorare (bistabil). Pentru a evita generarea unorelemente de memorare (atunci când nu este necesar), trebuie să se asigneze valori variabilelor sau semnalelor înfiecare ramură condiţională.

8.4.3. Registre

În Exemplul 8.46 se descrie un registru de 8 biţi printr-un proces similar celui din Exemplul 8.44, cudeosebirea că d şi q sunt vectori.

Exemplul 8.46library 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 isbegin process (clk) begin if (clk'event and clk = '1') then q <= d; end if; end process;end ex_reg;

8.4.4. Numărătoare

În Exemplul 8.47 se descrie un numărător de 3 biţi.

Exemplul 8.47library 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 isbegin count: process (clk) begin if (clk'event and clk = '1') then num <= num + 1; end if; end process count;end num3_integer;

Structura sistemelor de calcul - Lucrarea de laborator Nr. 836

Î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 saustd_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 tipstd_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 sin-tezei 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.3defineş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 înpachetul numeric_std al standardului 1076.3.

Exemplul 8.48 reprezintă Exemplul 8.47 modificat pentru a se utiliza tipul unsigned pentru ieşireanumărătorului.

Exemplul 8.48library 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 isbegin 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 pentrutipul std_logic. Deşi acestea nu sunt pachete standard, ele se utilizează adesea de către proiectanţi, deoarecepermit de obicei operaţii aritmetice şi relaţionale cu tipul std_logic, din acest punct de vedere fiind chiar maiutile decât pachetul numeric_std. De asemenea, aceste pachete nu necesită utilizarea a două tipuri suplimenta-re (signed, unsigned) în plus faţă de tipul std_logic_vector şi nici a funcţiilor necesare conversiei întreaceste tipuri. La utilizarea unuia din aceste pachete pentru operaţiile aritmetice, sistemul de sinteză va utilizapentru tipul std_logic_vector o reprezentare fără semn sau una cu semn (de obicei în C2), şi va genera com-ponentele aritmetice corespunzătoare.

8.4.5. Resetarea componentelor sincrone

Exemplele anterioare nu fac referire la resetarea componentelor descrise sau la condiţiile iniţiale. Stan-dardul 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 atipului semnalului respectiv. Pentru ca circuitele reale să fie aduse într-o stare cunoscută la iniţializare, trebuieutilizate semnale de resetare şi setare (preset).

Figura 8.20 ilustrează un bistabil de tip D cu un semnal de resetare asincronă. Acest bistabil poate fidescris în modul prezentat în Exemplul 8.49.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 37

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

Exemplul 8.49architecture exemplu_r of bist_d is -- 1begin -- 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; -- 10end exemplu_r; -- 11

Dacă semnalul reset este activat, semnalul q va fi setat la '0', indiferent de valoarea semnalului deceas. Funcţia rising_edge este definită în pachetul std_logic_1164, având rolul de a detecta frontul cres-că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 simu-lare funcţia rising_edge, de exemplu, va asigura că tranziţia este de la '0' la '1', şi nu va ţine cont de alte tran-ziţ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 modi-fică 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 interio-rul porţiunii procesului care este sincronă cu ceasul, după cum se indică în Exemplul 8.50.

Exemplul 8.50architecture exemplu_r_sinc of bist_d isbegin 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 urmasintezei se generează un bistabil D care resetat în mod sincron atunci când semnalul reset este activ şi apare unfront crescător al semnalului de ceas. Deoarece bistabilele circuitelor PLD nu dispun de obicei de intrări de setaresau resetare sincronă, implementarea acestor intrări necesită utilizarea unor resurse logice suplimentare (Figura8.21).

Structura sistemelor de calcul - Lucrarea de laborator Nr. 838

Figura 8.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). Uneorisunt necesare două semnale asincrone: atât un semnal de resetare, cât şi unul de setare. Exemplul 8.51 prezintăun numărător de 8 biţi cu semnale asincrone de resetare şi setare.

Exemplul 8.51library 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 isbegin 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 unorvalori la registrele numărătorului. Combinaţia de semnale de resetare şi setare din acest exemplu ridică o pro-blemă legată de sinteză. Construcţia if-then-else utilizată în cadrul procesului implică o precedenţă – faptulcă numărătorului trebuie să i se asigneze valoarea "11111111" numai atunci când semnalul set este activ şisemnalul reset nu este activ. Logica din Figura 8.22(a) asigură această condiţie.

Figura 8.22. Rezultatul sintezei descrierii din Exemplul 8.51: (a) logica suplimentară asigură ca semnalul resetsă 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 recu-noaşte faptul că acesta nu reprezintă efectul dorit şi că prin construcţia bistabilelor este dominant fie semnalul

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 39

reset, fie semnalul set. Astfel, în funcţie de algoritmul utilizat de programul de sinteză, descrierea din Exem-plul 8.51 va genera fie logica din Figura 8.22(a), fie cea din Figura 8.22(b). Multe circuite CPLD care permitresetarea sau setarea prin termeni produs pot implementa ambele variante. De asemenea, majoritatea circuitelorFPGA dispun de resursele necesare pentru implementarea resetării sau setării prin termeni produs. Totuşi, întimp ce majoritatea circuitelor FPGA permit resetarea sau setarea eficientă prin semnale globale, de obicei aces-tea nu dispun de resurse pentru resetarea sau setarea eficientă prin termeni produs, caz în care implementarea dinFigura 8.22(b) este preferată.

În toate exemplele anterioare în care există semnale de resetare sau setare s-a utilizat instrucţiunea ifsau funcţia rising_edge pentru descrierea circuitelor sincrone. Pentru descrierea acestor circuite se poate utili-za şi instrucţiunea wait until, dar în acest caz semnalele de resetare şi setare trebuie să fie sincrone. Aceastadeoarece pentru descrierile destinate sintezei instrucţiunea wait trebuie să fie prima din cadrul unui proces, ast-fel încât toate instrucţiunile care urmează vor descrie o logică sincronă.

8.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. Înplus, 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 8.52 prezintă descrierea modificată a numărătorului din Exemplul 8.51 pentru a utiliza ieşiricu trei stări. Acest numărător nu dispune de un semnal de setare asincronă. De data acesta s-a utilizat pachetulstd_arith şi tipul std_logic_vector pentru data şi num.

Exemplul 8.52library 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 8.51: sem-nalul oe, prevăzut pentru controlul ieşirilor cu trei stări, şi semnalul local num_tmp declarat în cadrul arhitectu-

Structura sistemelor de calcul - Lucrarea de laborator Nr. 840

rii. Procesul etichetat cu oep este utilizat pentru a descrie ieşirile cu trei stări ale numărătorului. Dacă semnaluloe nu este activat, ieşirile sunt trecute în starea de înaltă impedanţă. Descrierea procesului oep este în concor-danţă cu operarea unui buffer cu trei stări (Figura 8.23).

Figura 8.23. Buffer cu trei stări.

Numărătorul din exemplele precedente poate fi modificat astfel încât pentru ieşirile acestuia să se utili-zeze 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 8.53, semnalul de validare a ieşirilor unui buffer cu trei stări este definit în mod implicit.

Exemplul 8.53mux: 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 generareaacestor buffere se pot utiliza şi descrieri structurale, cum este construcţia for generate. Această construcţieva fi descrisă în capitolul 10.

8.5. Aplicaţii8.5.1. Identificaţi şi corectaţi erorile din următoarea descriere:library ieee; -- 1use ieee.std_logic.all; -- 2entity 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); -- 6end t_c; -- 7architecture t_c of t_c is -- 8 signal num: std_logic_vector (7 downto 0); -- 9begin -- 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 - Lucrarea de laborator Nr. 8 41

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

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

8.5.2. Analizaţi exemplele prezentate care se referă la instrucţiunile secvenţiale. Simulaţi descriereacomparatorului (Exemplul 8.12), a numărătorului (Exemplul 8.21), a circuitului pentru compararea biţilor deacelaşi rang a doi vectori (Exemplul 8.26), a circuitului pentru contorizarea biţilor de '1' ai unui vector (Exemplul8.27).

8.5.3. Scrieţi o secvenţă pentru setarea semnalului x la valoarea funcţiei ŞI logic între toate liniile uneimagistrale de 8 biţi a_bus[7:0].

8.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;

8.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;

8.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;

8.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;

8.5.8. Simulaţi funcţionarea circuitelor combinaţionale descrise în exemplele 8.40, 8.41, 8.42 şi 8.43.

8.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.

8.5.10. Descrieţi un multiplexor 4:1 de 8 biţi utilizând o instrucţiune case. Intrările multiplexoruluisunt a[7:0], b[7:0], c[7:0], d[7:0], s[1:0], iar ieşirile sunt q[7:0].

Structura sistemelor de calcul - Lucrarea de laborator Nr. 842

8.5.11. Realizaţi un decodificator din codul BCD pentru afişajul cu 7 segmente. Intrăriledecodificatorului sunt bcd[3:0], iar ieşirile sunt led[6:0].

8.5.12. Proiectaţi o memorie FIFO cu capacitatea de 8 cuvinte de câte 9 biţi. Schema bloc a acestei me-morii FIFO este prezentată în Figura 8.24.

Figura 8.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). Atuncicând semnalul de citire nu este activat, ieşirea memoriei trebuie adusă în starea de înaltă impedanţă. La activareasemnalului 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 caretrebuie citit, respectiv registrul care trebuie înscris. Pentru incrementarea pointerilor de citire şi de scriere se uti-lizează semnalele rdinc, respectiv wrinc. Semnalele rdptrclr şi wrptrclr resetează pointerii de citire şi de scrierepentru ca aceştia să adreseze primul registru al memoriei FIFO.

8.5.13. Compilaţi descrierea registrului de 8 biţi din Exemplul 8.46 şi simulaţi funcţionarea acestui re-gistru.

8.5.14. Modificaţi descrierea registrului de 8 biţi din Exemplul 8.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 sin-cron. Verificaţi apoi funcţionarea registrului.

8.5.15. Compilaţi descrierea numărătorului de 3 biţi din Exemplul 8.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.

8.5.16. Modificaţi descrierea numărătorului de 8 biţi având ieşiri cu trei stări din Exemplul 8.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şirecu trei stări numit coliziune, care va fi activat atunci când semnalele enable şi load sunt ambele active, cucondiţia ca ieşirile numărătorului să fie activate prin semnalul oe.

Structura sistemelor de calcul - Lucrarea de laborator Nr. 8 43

8.5.17. Modificaţi descrierea numărătorului de 8 biţi din Exemplul 8.52, astfel încât pentru ieşirileacestuia 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.

8.5.18. Proiectaţi un circuit de înmulţire binară pentru numere de câte 8 biţi reprezentate în mărime şisemn utilizând metoda directă. Utilizaţi procese sau instrucţiuni concurente de asignare a semnalelor pentru fie-care element al circuitului.

8.5.19. Proiectaţi un circuit de înmulţire binară pentru numere de câte 8 biţi reprezentate în complementfaţă de 2 utilizând metoda Booth. Utilizaţi procese sau instrucţiuni concurente de asignare a semnalelor pentrufiecare element al circuitului.

8.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 fiecareelement al circuitului.

8.5.21. Proiectaţi un circuit de împărţire binară pentru numere reprezentate în mărime şi semn utilizândmetoda 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 8biţi. Utilizaţi procese sau instrucţiuni concurente de asignare a semnalelor pentru fiecare element al circuitului.

8.5.22. Proiectaţi un circuit de înmulţire zecimală pentru numere de câte 4 cifre utilizând metoda com-ponenţilor din dreapta şi din stânga. Utilizaţi procese sau instrucţiuni concurente de asignare a semnalelor pentrufiecare element al circuitului.

8.5.23. Descrieţi în limbajul VHDL arhitectura care utilizează microprogramarea pe orizontală (Figura4.5). Utilizaţi procese sau instrucţiuni concurente de asignare a semnalelor pentru fiecare element al arhitecturii.

8.5.24. Modificaţi descrierea arhitecturii microprogramate pentru a utiliza microprogramarea pe verti-cală (Figura 4.6).