Documente Academic
Documente Profesional
Documente Cultură
Laboratoare PSN
Laboratoare PSN
PACHETE STANDARDIZATE
-- Pachetele conforme cu standardul IEEE 1164
-- LEGENDĂ
-- () = „Grupare”
-- [ ] = „Opţional”
-- {} = „În mod repetat”
-- | = „Alternative”
-- MAJUSCULE = „Identificator utilizator”
-- Prescurtări
-- c ::= „comutativ”
-- b ::= BIT
-- bv ::= BIT_VECTOR
-- u/l ::= STD_ULOGIC/STD_LOGIC
-- uv ::= STD_ULOGIC_VECTOR
-- lv ::= STD_LOGIC_VECTOR
-- un ::= UNSIGNED
-- sg ::= SIGNED
-- in ::= INTEGER
-- na ::= NATURAL
-- sm ::= SMALL_INT (subtype INTEGER range 0 to 1)
1. Scopul lucrării
2. Consideraţii teoretice
A <= B and C;
A<= B and C ;
22 LIMBAJUL VHDL
O instrucţiune se poate întinde pe mai multe linii, atâta timp cât
sfârşitul de linie nu este plasat în mijlocul unui identificator, al unui simbol
de operator sau al unui literal.
3. Desfăşurarea lucrării
1. Scopul lucrării
2. Consideraţii teoretice
library biblioteca_în_care_este_păstrată_unitatea_primară;
...
use numele_entităţii; -- dacă unitatea primară e o
--specificaţie de entitate
2.4.1 Entitatea
Entitatea descrie interfaţa unică dintre arhitecturi şi mediul exterior,
iar arhitectura descrie funcţionalitatea entităţii. Ansamblul poate fi văzut şi
utilizat, la un nivel superior, ca o componentă.
În funcţie de gradul de fineţe sau, pur şi simplu, de nivelul de
descriere (structural, comportamental, flux de date sau hibrid) care a fost
ales pentru descrierea funcţionalităţii, vom putea avea mai multe arhitecturi
diferite pentru aceeaşi entitate.
Această grupare în entităţi şi arhitecturi conferă o mare modularitate
modelării în VHDL. Modificarea unei arhitecturi sau înlocuirea sa nu va
avea nici o repercusiune asupra unităţilor de proiectare care fac referire la
entitatea corespunzătoare. Entitatea rămâne identică şi constituie singurul
element cunoscut de către mediul exterior; mediul nu „vede” arhitectura.
Dimpotrivă, informaţiile cuprinse în entitate sunt cunoscute de către
diversele sale arhitecturi. Toate aceste informaţii sunt opţionale. Ele sunt de
trei feluri:
- declaraţii de parametri generici;
- declaraţii de porturi;
- instrucţiuni.
Sintaxa unei entităţi este următoarea:
entity numele_entităţii is
{generic (listă de parametri generici)}
{port (listă de porturi)}
{begin
listă de instrucţiuni concurente}
end {numele_entităţii};
28 Limbajul VHDL
Acoladele delimitează informaţiile opţionale.
Numele entităţii este un identificator care trebuie să fie unic în
biblioteca dată. Pentru a desemna o pereche entitate / arhitectură, se notează:
numele_entităţii(numele_arhitecturii)
A B
1 Sunt acceptate numai instrucţiunile concurente al căror proces echivalent este pasiv, adică:
instrucţiunile concurente assert, anumite apeluri de proceduri şi anumite procese (aceste
instrucţiuni sunt prezentate ulterior).
UNITĂŢI FUNDAMENTALE DE PROIECTARE 29
Acestui sumator îi corespunde următoarea entitate:
entity SUMATOR_COMPLET is
port(A, B, CIN: in BIT;
S, COUT: out BIT);
end SUMATOR_COMPLET;
component POARTA_SAU
port(A, B: in BIT;
S: out BIT);
end component;
Observaţie
Noţiunea de timp nu intervine într-o descriere structurală, care nu
reprezintă decât interconectarea unor elemente.
V = A XOR B
S = V XOR CIN
COUT = (A and B) OR (V and CIN)
c) Descrierea comportamentală
Această descriere este bazată pe tabelul de adevăr al sumatorului:
A B CIN S COUT
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1
2.4.3 Configuraţia
Pentru a simula o instanţă a unei componente este necesară
cunoaşterea perechii entitate / arhitectură pe care aceasta o „utilizează”.
Această informaţie poate fi dată direct sau poate proveni de la configuraţie.
Începând cu versiunea '93 a VHDL există posibilitatea asocierii
directe şi într-o singură linie a unei perechi entitate / arhitectură cu o instanţă
a unei componente. Aceasta se realizează cu ajutorul unei instrucţiuni
numite „instanţiere directă” (descrisă în lucrarea nr. 9). De fapt, însăşi
noţiunea de „componentă” nu mai este necesară. Instrucţiunea este uşor de
pus în aplicare, dar suferă de lipsă de forţă şi de flexibilitate: numele entităţii
şi al arhitecturii sunt fixate într-un loc precis al codului sursă. Configuraţia –
deşi este un concept mai greu de asimilat - oferă mult mai multă
flexibilitate.
Conceptele de „componentă” şi de „configuraţie” sunt primordiale în
VHDL. De fapt, există două tipuri de configuraţii posibile:
a) De fiecare dată când utilizăm o componentă într-o descriere
VHDL, există posibilitatea de a o configura imediat, ceea ce înseamnă să
specificăm modelul al cărei instanţă este, parametrii săi (dacă este generic)
şi corespondenţa dintre porturile sale (numite porturi formale) şi porturile
actuale.
34 Limbajul VHDL
b) Cu toate acestea, în unele cazuri poate părea mai judicios să
amânăm această configuraţie pentru a o plasa în unitatea de proiectare cu
acelaşi nume (cu ajutorul cuvântului cheie configuration).
Forţa acestei unităţi de proiectare creşte atunci când este separată de
restul descrierii. Astfel, fără a modifica (deci fără a mai recompila) alte
unităţi de proiectare, va fi posibil, de exemplu, să schimbăm nivelul
descrierii unei componente (configurând o nouă arhitectură, poate chiar o
altă entitate).
Aspectele prezentate anterior în cazul unei componente sunt la fel de
adevărate şi în cazul unui bloc, element ierarhic intern unei arhitecturi care
va fi prezentat ulterior (lucrarea nr. 9).
Sintaxa unei configuraţii este următoarea:
library MY_PROJECT_SIM;
use MY_PROJECT_SIM.all;
configuration cfg_test_PROIECT of test_PROIECT is...
Observaţie
Dacă această entitate, referită în mod explicit, are mai multe
arhitecturi, nu este posibil s-o alegem direct (compilatorul va selecta
arhitectura cea mai recent compilată). O soluţie constă în definirea unei
configuraţii specifice pentru o anumită pereche entitate / arhitectură şi în
alegerea perechii corecte.
package P1_PKG is
--Definirea unui tip enumerat
type CIT_SCR is (SCRIERE, CITIRE);
--Definirea unei constante
constant DIM_MAX: INTEGER:=200;
--Definirea de sub-tipuri
subtype DIM is INTEGER range 0 to DIM_MAX;
subtype CIT_SCR_BIT is BIT;
--Definirea de constante cu iniţializare ulterioară
constant SCRIERE_BIT: CIT_SCR_BIT;
constant CITIRE_BIT: CIT_SCR_BIT;
--Declararea unui semnal
signal COMANDĂ_MEMORIE: CIT_SCR;
--Declararea unei funcţii
function CDĂ_SPRE_BIT (C: in CIT_SCR) return CIT_SCR_BIT;
--Declararea unei proceduri
procedure CDĂ_SPRE_BIT (C: in CIT_SCR; B: out CIT_SCR_BIT);
end P1_PKG;
Observaţie
Este interzisă declararea semnalelor: corpul unui pachet face parte
din domeniul secvenţial.
40 Limbajul VHDL
Vom considera un exemplu extrem de simplu: următorul pachet va
trebui să exporte două funcţii care returnează, respectiv, cel mai mic şi cel
mai mare dintre două numere întregi.
package SIMPLU is
function MIN(A,B: INTEGER) return INTEGER;
function MAX(A,B: INTEGER) return INTEGER;
end SIMPLU;
--Definirea funcţiei
function CDĂ_SPRE_BIT (C: in CIT_SCR) return CIT_SCR_BIT is
begin
case C is
when CITIRE => return CITIRE_BIT;
when SCRIERE => return SCRIERE_BIT;
end case;
end;
UNITĂŢI FUNDAMENTALE DE PROIECTARE 41
--Definirea procedurii
procedure CDĂ_SPRE_BIT(C: in CIT_SCR;B: out CIT_SCR_BIT) is
begin
case C is
when CITIRE => B:= CITIRE_BIT;
when SCRIERE => B:= SCRIERE_BIT;
end case;
end;
end P1_PKG;
3. Desfăşurarea lucrării
1. Scopul lucrării
2. Consideraţii teoretice
Deşi în VHDL există cinci tipuri de moduri posibile ale unui semnal
(in, inout, out, buffer şi linkage) este recomandat să se utilizeze numai
primele trei dintre ele, deoarece ultimele două nu sunt acceptate de toate
instrumentele de sinteză. Cele mai folosite trei moduri pot fi descrise astfel:
- modul in: datele pot fi citite în interiorul modulului, dar nu pot fi
scrise de către arhitectura internă a modulului;
SEMNALE. PARAMETRI GENERICI.CONSTANTE 45
- modul out: datele pot fi generate în interiorul arhitecturii, dar nu
pot fi citite;
- modul inout: datele pot fi citite şi scrise în interiorul arhitecturii.
WE
CS_ROM CS_RAM
entity MEMORIE_ROM is
port(A_ROM: in BIT_VECTOR (3 downto 0); -- Adresele
CS_ROM: in BIT; -- Semnal selecţie cip, „Chip Select”
D_ROM: out BIT_VECTOR(7 downto 0)); -- Ieşiri de date
end MEMORIE_ROM;
entity MEMORIE_RAM is
port(A_RAM: in BIT_VECTOR (3 downto 0); -- Adresele
CS_RAM: in BIT; -- Semnal selecţie cip, „Chip Select”
WE: in BIT; -- Semnal validare scriere, „Write Enable”
D_RAM: inout BIT_VECTOR(7 downto 0)); -- Bidirecţional
end MEMORIE_RAM;
Observaţii
1. Cuvântul cheie signal nu este necesar în declaraţia porturilor, deoarece
fiecare port este prin definiţie un semnal.
2. Semnalele interne nu au nevoie de declaraţii de mod (in, inout, out etc.)
3. Există posibilitatea să se specifice o valoare iniţială pentru fiecare
semnal intern.
Registrul C
7 0
7 0 7 0
Unitate
Aritmetică
Logică
7 0
Reacţie
Transport
Registrul A Registrul B
7 0 7 0
Câtul Q Restul R
entity UNITATE_DE_EXECUŢIE is
port (X, Y: in BIT_VECTOR (7 downto 0);
Q,R: out BIT_VECTOR (7 downto 0));
-- X, Y, Q şi R sunt semnale externe
end entity UNITATE_DE_EXECUŢIE;
architecture UEA of UNITATE_DE_EXECUŢIE is
signal C: BIT_VECTOR (7 downto 0);
signal REACŢIE: BIT_VECTOR (7 downto 0);
signal TRANSPORT: BIT; --A,B: registre de deplasare pe 8 biţi
-- C, REACŢIE şi TRANSPORT sunt semnale interne
begin
-- Descrierea structurii interne a Unităţii de execuţie
...
end UEA;
Q
Q
NQ
T0 + (2 × delta) NQ
T0
T0
a) b)
Figura 3.5 Întârzierile „delta”: a) punctul de vedere al simulatorului;
b) punctul de vedere al proiectantului
NQ
T0 T0 + 10 ns
T0 + 5 ns
Orice impuls prezent pe linia REF, a cărui durată este mai mică
decât 10 nanosecunde, nu va fi transmis pe SEMNAL1;
10 ns 50 ns 100 ns
Figura 3.7 Modelele de propagare inerţial şi transport
SEMNAL1 < = REF after 10 ns; sau SEMNAL1 <= inertial REF after 10 ns;
Filtrat! Păstrat!
10 ns 50 ns 100 ns
Pentru a asigna valori unui agregat, adică pentru a-l putea folosi în
membrul stâng al asignării, trebuie ca tipul agregatului să fie declarat şi ca
identificarea acestui tip să se poată face fără ambiguitate din punctul de
vedere al părţii drepte a instrucţiunii de asignare. Nu este permisă utilizarea
unei expresii calificate (tip_ obiect ‘(expresie) sau tip_obiect ‘agregat) în
membrul stâng.
Presupunând că semnalele A şi B sunt de tipul BIT şi că se cunoaşte
tipul BIT_VECTOR, am putea fi tentaţi să scriem:
Observaţie
La utilizarea unui agregat într-un element de formă de undă, aceleaşi
restricţii interzic utilizarea cuvântului cheie others; tipul agregatului din
stânga trebuie să poată fi identificat fără ambiguitate.
TRANSPORT INERŢIAL
A doua tranzacţie
Scrie peste prima
are loc înaintea Scrie peste prima tranzacţie
tranzacţie
primei tranzacţii.
A doua tranzacţie Adaugă a doua Scrie peste prima tranzacţie
are loc după prima tranzacţie la dacă valorile sunt diferite;
tranzacţie. semnal dacă nu, ambele sunt păstrate
begin
process
begin
IEŞIRE <= ‘1’ after 10 ns; -- prima tranzacţie
IEŞIRE <= ‘0’ after 5 ns; -- a doua tranzacţie
wait;
end process;
end;
begin
process
begin
IEŞIRE <= transport ‘1’ after 10 ns; -- prima tranzacţie
IEŞIRE <= transport ‘0’ after 5 ns; -- a doua tranzacţie
wait;
end process;
end;
Ieşire X 0
0 ns 5 ns 10 ns 15 ns
Figura 3.9
2) Inerţial – tranzacţia 2 are loc după tranzacţia 1, valori similare (figura
3.10).
begin
process
begin
IEŞIRE <= ‘0’ after 10 ns; -- prima tranzacţie
IEŞIRE <= ‘0’ after 15 ns; -- a doua tranzacţie
wait;
end process;
end;
SEMNALE. PARAMETRI GENERICI.CONSTANTE 57
Ieşire X 0
0 ns 5 ns 10 ns 15 ns
Figura 3.10
begin
process
begin
IEŞIRE <= ‘1’ after 10 ns; -- prima tranzacţie
IEŞIRE <= ‘0’ after 15 ns; -- a doua tranzacţie
wait;
end process;
end;
Ieşire X 0
0 ns 5 ns 10 ns 15 ns
Figura 3.11
4) Transport – tranzacţia 2 are loc după tranzacţia 1 (figura 3.12)
begin
process
begin
IEŞIRE <= transport ‘1’ after 10 ns; -- prima tranzacţie
IEŞIRE <= transport ‘0’ after 15 ns; -- a doua tranzacţie
wait;
end process;
end;
58 LIMBAJUL VHDL
Ieşire X 1 0
0 ns 5 ns 10 ns 15 ns
Figura 3.12
POARTA_ŞI: block
generic (NUMĂR_INTRĂRI: NATURAL := 2);
port (INTRĂRI: in BIT_VECTOR (1 to NUMĂR_INTRĂRI);
IEŞIRE: out BIT);
generic map (NUMĂR_INTRĂRI => 8); -- Instanţierea unei porţi
-- ŞI cu 8 intrări
begin --Zona de instrucţiuni din cadrul blocului
process (INTRĂRI)
variable V: BIT:=’1’;
begin
for I in 1 to NUMĂR_INTRĂRI loop
V:= V and INTRĂRI(I);
end loop;
IEŞIRE <= V;
end process;
end POARTA_ŞI;
entity RECUNOAŞTERE is
generic (SECVENŢA: BIT_VECTOR);
port (INTRARE, TACT: in BIT;
DETECTAT: out BIT);
end RECUNOAŞTERE;
Observaţii
1. Testul TACT = ’1’ e utilizabil deoarece TACT este de tipul BIT. Dacă, de
exemplu, TACT ar putea lua valorile ‘X’, ‘0’, ‘1’ sau ‘Z’, acest test ar fi
adevărat (în mod greşit) în decursul trecerilor de la ‘X’ la ‘1’ sau de la ‘Z’ la
‘1’. Ar trebui deci regândită expresia utilizând atribute adecvate.
2. Descrierea de mai sus se pretează foarte bine la o transformare în
arhitectură recursivă.
2.7 Constante
3. Desfăşurarea lucrării
1. Scopul lucrării
În lucrare se prezintă toţi operatorii din VHDL, precum şi literalii
utilizaţi în cadrul limbajului. Sunt analizate pe larg tipurile de date utilizate
în cadrul unei descrieri VHDL, împărţite în cele patru mari categorii: tipul
scalar, tipul compus, tipul acces şi tipul fişier. Se subliniază diferenţele
dintre anumite tipuri de date care pot crea confuzii.
2. Consideraţii teoretice
2.1 Operatori
Observaţie
Operatorii de semn au o prioritate mai mică decât operatorii de
înmulţire, ceea ce nu este normal.
Astfel, expresia 2* -3, care ar trebui să ia valoarea –6, va genera o
eroare (nu se poate evalua înmulţirea înaintea evaluării operatorului unar
„-“). Introducerea de paranteze va rezolva problema (se va scrie: 2*(-3)).
A = (A/B) * B + (A rem B)
2.2 Literali
Observaţie
Semnalele nu pot avea tipul acces; nici măcar un sub-element al unui
semnal nu poate avea acest tip.
Numai variabilele pot avea tipul acces; fişierele constituie o familie
cu totul specială de tipuri. Semnul de întrebare din figura 4.1 indică faptul
că fişierele pot fi văzute ca variabile a căror valoare nu poate fi modificată.
a) Tipurile enumerate
Toate declaraţiile de tip încep cu cuvântul cheie type. Pentru
declararea acestui tip de date, este suficientă indicarea valorilor simbolice
(identificatori sau caractere) pe care le poate lua. De exemplu:
b) Tipurile întregi
Tipurile numerice întregi pot fi văzute ca tipuri enumerate (ele
reprezintă un şir ce poate fi enumerat). Pe toate aceste tipuri sunt definiţi
operatorii aritmetici. Toate tipurile numerice întregi pot fi convertite implicit
într-un tip virtual numit UNIVERSAL_INTEGER, aspect care asigură
compatibilitatea tuturor tipurilor numerice.
Pentru a declara un tip numeric întreg este suficient să indicăm
intervalul pe care este definit cu ajutorul cuvântului cheie range. De
exemplu, porţiunea de cod VHDL de mai jos reprezintă declaraţia unui tip
enumerat întreg care variază între 1 şi 22, inclusiv capetele intervalului:
c) Tipurile flotante
La fel ca în cazul tipurilor numerice întregi, declaraţia unui tip
flotant se face prin specificarea capetelor intervalului său de definiţie (aceste
capete ale intervalului de definiţie trebuie să fie şi ele flotante):
d) Tipurile fizice
Aceste tipuri sunt foarte apropiate de tipurile întregi. În limbajul
VHDL există noţiunea de unitate de cantitate. De exemplu, în pachetul
STANDARD este definit tipul TIME, care este un tip fizic. Acesta este
singurul tip fizic predefinit şi el este utilizat de către simulator.
Un tip fizic este caracterizat de:
• Unitatea de bază (femtosecunda, pentru tipul TIME);
• Intervalul valorilor autorizate;
• O eventuală colecţie de sub-unităţi împreună cu corespondenţele
lor.
În cele ce urmează este prezentată definiţia tipului TIME din
pachetul STANDARD. Intervalul valorilor sale autorizate depinde de
implementare. În varianta de mai jos este propusă o codificare pe 64 de biţi:
Observaţie
Între număr şi unitatea de măsură există întotdeauna un caracter
„spaţiu”. Acest aspect nu este specificat explicit în norma VHDL, aşa că
fiecare constructor de instrumente VHDL realizează propria sa
implementare, în care poate să ţină sau nu cont de aceasta.
a) Tablourile
Structurile omogene se descriu în VHDL prin tablouri. De exemplu,
o magistrală de semnale văzută ca o structură omogenă de biţi poate fi
reprezentată printr-un tablou. Acest lucru este făcut în pachetul
STANDARD prin declararea tipului BIT_VECTOR.
Elementele acestor structuri sunt accesibile cu ajutorul unuia sau mai
multor indecşi (numărul acestora poate fi oarecare). Un tabel cu un singur
index este numit vector.
Definirea unui tablou necesită specificarea tipului şi a numărului
indecşilor şi a tipului elementelor tabloului. Tipul indecşilor poate fi orice
tip discret (enumerat sau întreg). Tipul elementelor poate fi oricare, cu
excepţia tipului fişier.
Există două tipuri de tablouri:
- tablourile constrânse, în care intervalul de variaţie a indecşilor
este cunoscut cu anticipaţie. Sensul de variaţie al indecşilor este
specificat cu ajutorul cuvintelor cheie to şi downto. Iată câteva
definiţii de tablouri constrânse:
b) Articolele
Spre deosebire de tablouri, articolele pot conţine elemente de tipuri
diferite. Aceste elemente se mai numesc şi câmpuri şi sunt desemnate prin
nume şi nu prin index, ca în cazul tablourilor. Pentru a descrie un articol,
este suficient să enumerăm câmpurile care fac parte din el între cuvintele
cheie record şi end record.
Iată un exemplu de definiţie a unui tip articol:
A <= B;
DEALLOCATE(A);
c) Funcţia ENDFILE
Această funcţie primeşte un parametru de intrare de tip fişier şi ne
permite să aflăm dacă am ajuns la sfârşitul fişierului. Ea returnează
valoarea FALSE dacă se mai poate citi cel puţin încă o valoare din
fişierul respectiv.
Dacă fişierul a fost utilizat în mod out (în scriere), rezultatul boolean
este întotdeauna adevărat. În cazul în care se va încerca efectuarea
unei operaţii de citire (READ) asupra unui fişier pentru care apelul
funcţiei ENDFILE ar returna valoarea „adevărat”, se va genera o
eroare la simulare.
Observaţie
Pentru tablourile neconstrânse, procedura READ returnează, pe
lângă valoarea citită din fişier, şi lungimea tabloului. Atunci, profilul
funcţiei nu este cel de mai sus, ci următorul:
Observaţie
Notaţia aleasă, “1010” este deosebit de ambiguă. Acelaşi exemplu
rămâne valabil şi pentru notaţia “QWERTY”, chiar dacă ambiguitatea cu
tipul BIT_VECTOR pare exclusă (din punct de vedere uman): compilatorul
nu va face presupuneri în privinţa conţinutului, ci va reacţiona la notaţia “”!
Tipul_spre_care_se_face_conversia (valoarea_de_convertit)
3. Desfăşurarea lucrării
3.1 Se va exersa definirea tuturor tipurilor de date şi operatori. Se va
crea un tip fizic numit VOLUM şi un tip fizic VALUTĂ pentru
conversia între diferite monede.
3.2 Se va crea o listă simplu înlănţuită cu elemente de tip acces, cu
alocări şi dealocări.
3.3 Se va crea un modul REGISTRU_DE_DEPLASARE, folosind
operatorii cei mai adecvaţi pentru gestionarea datelor interne.
3.4 Se va crea o unitate aritmetică-logică, în care intrările şi ieşirile
se vor exprima sub formă de articole şi care poate efectua
următoarele operaţii, pe cei doi operanzi de intrare de tip întreg
INTEGER: AND, OR, Înmulţire cu o putere a lui 2, Împărţire la
un număr putere a lui 2, adunare şi scădere.
LUCRAREA NR. 5
ATRIBUTE
1. Scopul lucrării
Lucrarea prezintă pe larg toate atributele existente în VHDL, atât
cele predefinite cât şi cele ce pot fi definite de către proiectant. Se oferă
exemple în cazul fiecărui atribut şi se explică pe larg modul lor de utilizare.
2. Consideraţii teoretice
2.1 Definiţie
Un atribut este o caracteristică asociată unui tip sau unui obiect (de
exemplu, numărul de elemente ale unui tablou) care va putea fi cunoscută în
mod dinamic în cursul rulării programului.
Atributele se notează prin adăugarea unui apostrof după numele
tipului sau al obiectului. Astfel, de exemplu, cel mai mare număr întreg care
poate fi reprezentat se scrie INTEGER'HIGH.
Există două mari clase de atribute:
- atribute predefinite;
- atribute care urmează să fie definite de către proiectant.
obiect_pe_care_operează_atributul'nume_atribut(parametri)
T'BASE
Rezultatul său este tipul de bază al lui T, unde T poate fi orice tip sau
sub-tip. Acest atribut nu este permis decât în expresia prefixului unui alt
atribut (de exemplu T'BASE'LEFT).
T'HIGH
Rezultatul său este o valoare de tipul T. Prefixul T trebuie să fie de
tip scalar sau să fie un sub-tip scalar. Valoarea returnată este cea mai mare
valoare implementată a tipului T.
88 LIMBAJUL VHDL
T'LOW
Rezultatul său este o valoare de tipul T. Prefixul T trebuie să fie de
tip scalar sau să fie un sub-tip scalar. Valoarea returnată este cea mai mică
valoare implementată a tipului T.
În cazul tipului ADRESĂ definit la începutul acestei secţiuni,
ADRESĂ'LOW este egal cu 0.
T'LEFT
Rezultatul său este o valoare de tipul T. Prefixul T trebuie să fie de
tip scalar sau să fie un sub-tip scalar. Valoarea returnată corespunde limitei
din stânga a tipului T; aceasta nu trebuie confundată cu cea mai mică
valoare a lui T. T'LEFT constituie valoarea de iniţializare implicită a tuturor
tipurilor scalare.
Pentru tipul INTEGER, INTEGER'LEFT = INTEGER'LOW.
Pentru tipul NIVEL, NIVEL'LEFT = 'U'.
Pentru tipul ADRESĂ, ADRESĂ'LEFT = 7.
T'RIGHT
Rezultatul său este o valoare de tipul T. Prefixul T trebuie să fie de
tip scalar sau să fie un sub-tip scalar. Valoarea returnată corespunde limitei
din dreapta a tipului T; aceasta nu trebuie confundată cu cea mai mare
valoare a lui T.
Pentru tipul INTEGER, INTEGER'RIGHT = INTEGER'HIGH.
Pentru tipul NIVEL, NIVEL'RIGHT = 'Z'.
Pentru tipul ADRESĂ, ADRESĂ'RIGHT = 0.
T'POS (X)
Acest atribut este o funcţie de parametru X; X este de tipul de bază
al lui T. Prefixul T este un tip sau un sub-tip enumerat sau fizic. Valoarea
returnată de către această funcţie este un întreg universal
ATRIBUTE 89
(UNIVERSAL_INTEGER) care dă poziţia valorii parametrului X în cadrul
enumerării. Poziţia primului element este zero.
De exemplu, TIME'POS (1 ns) este de tipul
UNIVERSAL_INTEGER.
T'VAL (X)
Acest atribut este o funcţie de parametru X; X este o expresie de tip
întreg. Prefixul T este un tip sau un sub-tip enumerat sau fizic. Valoarea
returnată de către această funcţie este cea a cărei poziţie este egală cu X.
Poziţia primului element al unei enumerări este zero.
De exemplu, NIVEL'VAL(NIVEL'POS('Z')) are valoarea 'Z'.
T'SUCC (X)
Acest atribut este o funcţie de parametru X; X este de tipul de bază
al lui T. Prefixul T este un tip sau un sub-tip enumerat sau fizic. Valoarea
returnată de către această funcţie este cea a cărei poziţie este egală cu X + 1.
Observaţie
Se va genera o eroare dacă X este egal cu T'BASE'HIGH.
T'PRED (X)
Acest atribut este o funcţie de parametru X; X este de tipul de bază
al lui T. Prefixul T este un tip sau un sub-tip enumerat sau fizic. Valoarea
returnată de către această funcţie este cea a cărei poziţie este egală cu X - 1.
Observaţie
Se va genera o eroare dacă X este egal cu T'BASE'LOW.
Observaţie
Se va genera o eroare dacă X este egal cu T'BASE'LEFT.
T'RIGHTOF (X)
Acest atribut este o funcţie de parametru X; X este o expresie al cărei
tip este tipul de bază al lui T. Prefixul T este un tip sau un sub-tip enumerat
sau fizic. Valoarea returnată de către această funcţie este cea a cărei poziţie
se află la dreapta celei a lui X.
Observaţie
Se va genera o eroare dacă X este egal cu T'BASE'RIGHT.
T'ASCENDING
Acest atribut este o funcţie care returnează o valoare booleană TRUE
dacă intervalul tipului este crescător (to) şi FALSE în caz contrar (downto).
Prefixul T este un tip sau un sub-tip enumerat sau fizic.
NIVEL'ASCENDING este TRUE.
COD'ASCENDING este TRUE.
ADRESĂ'ASCENDING este FALSE.
T'IMAGE (X)
Acest atribut este o funcţie care are drept parametru o valoare de tip
scalar X şi care returnează un şir de caractere (de tip STRING) reprezentând
ATRIBUTE 91
valoarea respectivă. Prefixul T este deci un tip sau un sub-tip scalar. Acest
tip este acelaşi cu tipul lui X.
De exemplu, COD'IMAGE(ADD) returnează şirul de caractere
”ADD”. Acest atribut ar putea fi utilizat, de exemplu, în mesajul unei
instrucţiuni assert:
T'VALUE (X)
Acest atribut este o funcţie care are drept parametru un şir de
caractere (de tip STRING) şi returnează valoarea de tipul T care îi
corespunde. Dacă nu se recunoaşte nici o valoare a tipului, se generează o
eroare. Prefixul T este un tip sau un sub-tip scalar. X este deci de tipul
STRING. Acest atribut nu este sensibil la majuscule; este complementarul
atributului precedent.
COD'VALUE("ADD") returnează valoarea ADD de tipul COD.
COD'VALUE("adD") returnează valoarea ADD de tipul COD.
COD'VALUE("ALPHA") returnează o eroare.
obiect_pe_care_operează_atributul'nume_atribut(parametri)
A'LEFT[(N)]
Acest atribut este o funcţie care are drept parametru o expresie
statică de tip întreg universal N a cărui valoare nu trebuie să depăşească
numărul de dimensiuni ale tabloului A. N este opţional, având implicit
valoarea 1. Prefixul A poate fi un obiect de tip tablou, sau un obiect de sub-
tip constrâns de tablou, sau un alias.
Valoarea returnată de această funcţie este valoarea capătului din
stânga al celui de-al N-lea index în intervalul de variaţie al declaraţiei lui A.
Dacă A este un alias al unui obiect de tip tablou, valoarea returnată va fi
extrasă din declaraţia lui A şi nu din cea a obiectului.
Aşadar, NUME'LEFT este egal cu un întreg universal de valoare
necunoscută, în schimb NUME (NUME'LEFT) este egal cu 'M'.
PRENUME'LEFT este 8.
MEM'LEFT este 1.
VIZ'LEFT (2) este 1.
BL'LEFT este 16.
CV'LEFT este 0.
COD'LEFT este 3.
A'RIGHT[(N)]
Acest atribut este o funcţie care are drept parametru o expresie
statică de tip întreg universal N a cărui valoare nu trebuie să depăşească
numărul de dimensiuni ale tabloului A. N este opţional, având implicit
valoarea 1. Prefixul A poate fi un obiect de tip tablou, sau un obiect de sub-
tip constrâns de tablou, sau un alias.
Valoarea returnată de această funcţie este valoarea capătului din
dreapta al celui de-al N-lea index în intervalul de variaţie al declaraţiei lui
A. Dacă A este un alias al unui obiect de tip tablou, valoarea returnată va fi
extrasă din declaraţia lui A şi nu din cea a obiectului.
Aşadar, NUME'RIGHT este egal cu un întreg universal de valoare
necunoscută, în schimb NUME (NUME'RIGHT) este egal cu 'U'.
PRENUME'RIGHT este 1.
MEM'RIGHT este 256.
VIZ'RIGHT (2) este 1024.
BL'RIGHT este 1.
ATRIBUTE 93
CV'RIGHT este 7.
COD'RIGHT este 1.
A'HIGH[(N)]
Acest atribut este o funcţie care are drept parametru o expresie
statică de tip întreg universal N a cărui valoare nu trebuie să depăşească
numărul de dimensiuni ale tabloului A. N este opţional, având implicit
valoarea 1. Prefixul A poate fi un obiect de tip tablou, sau un obiect de sub-
tip constrâns de tablou, sau un alias de tablou.
Valoarea returnată de această funcţie este valoarea capătului superior
al celui de-al N-lea index în intervalul de variaţie al declaraţiei lui A. Dacă
A este un alias al unui obiect de tip tablou, valoarea returnată va fi extrasă
din declaraţia lui A şi nu din cea a obiectului.
Aşadar, NUME'HIGH este egal cu un întreg universal de valoare
necunoscută, în schimb NUME (NUME'HIGH) este egal cu 'U', deoarece
tipul STRING este definit cu un index de tip POSITIVE, care este crescător
de la 1 la INTEGER'HIGH.
PRENUME'HIGH este 8.
MEM'HIGH este 256.
VIZ'HIGH (2) este 1024.
BL'HIGH este 16.
CV'HIGH este 7.
COD'HIGH este 3.
A'LOW [(N)]
Acest atribut este o funcţie care are drept parametru o expresie
statică de tip întreg universal N a cărui valoare nu trebuie să depăşească
numărul de dimensiuni ale tabloului A. N este opţional, având implicit
valoarea 1. Prefixul A poate fi un obiect de tip tablou, sau un obiect de sub-
tip constrâns de tablou, sau un alias de tablou.
Valoarea returnată de această funcţie este valoarea capătului inferior
al celui de-al N-lea index în intervalul de variaţie al declaraţiei lui A. Dacă
A este un alias al unui obiect de tip tablou, valoarea returnată va fi extrasă
din declaraţia lui A şi nu din cea a obiectului.
Aşadar, NUME'LOW este egal cu un întreg universal de valoare
necunoscută, în schimb NUME (NUME'LOW) este egal cu 'M', deoarece
tipul STRING este definit cu un index de tip POSITIVE, care este crescător
de la 1 la INTEGER'HIGH.
94 LIMBAJUL VHDL
PRENUME'LOW este 1.
MEM'LOW este 1.
VIZ'LOW (2) este 1.
BL'LOW este 1.
CV'LOW este 0.
COD'LOW este 1.
A'RANGE [(N)]
Acest atribut este un interval de variaţie care are drept parametru o
expresie statică de tip întreg universal N a cărui valoare nu trebuie să
depăşească numărul de dimensiuni ale tabloului A. N este opţional, având
implicit valoarea 1. Prefixul A poate fi un obiect de tip tablou, sau un alias
de tablou, sau un obiect de sub-tip constrâns de tip tablou.
Valoarea returnată de această funcţie este intervalul de variaţie al
celui de-al N-lea index din declaraţia lui A. Dacă A este un alias al unui
obiect de tip tablou, valoarea returnată va fi extrasă din declaraţia lui A şi nu
din cea a obiectului.
Dacă cel de-al N-lea index este crescător, atunci A'RANGE(N) va
avea ca valoare intervalul de variaţie A'LEFT(N) to A'RIGHT(N). Dacă cel
de-al N-lea index este descrescător, atunci A'RANGE(N) va avea ca valoare
intervalul de variaţie A'RIGHT(N) downto A'LEFT(N).
Aşadar, NUME'RANGE este un interval de variaţie crescător căruia
nu i se cunosc decât valorile inferioară şi superioară. Totuşi, se poate scrie:
A'REVERSE_RANGE [(N)]
Acest atribut este un interval de variaţie care are drept parametru o
expresie statică de tip întreg universal N a cărui valoare nu trebuie să
ATRIBUTE 95
depăşească numărul de dimensiuni ale tabloului A. N este opţional, având
implicit valoarea 1. Prefixul A poate fi un obiect de tip tablou, sau un alias
de tablou, sau un obiect de sub-tip constrâns de tip tablou.
Valoarea returnată de această funcţie este intervalul de variaţie al
celui de-al N-lea index din declaraţia lui A, luat însă în ordine inversă. Dacă
A este un alias al unui obiect de tip tablou, valoarea returnată va fi extrasă
din declaraţia lui A şi nu din cea a obiectului.
Dacă cel de-al N-lea index este crescător, atunci
A'REVERSE_RANGE(N) va avea ca valoare intervalul de variaţie
A'RIGHT(N) downto A'LEFT(N). Dacă cel de-al N-lea index este
descrescător, atunci A'REVERSE_RANGE(N) va avea ca valoare intervalul
de variaţie A'LEFT(N) to A'RIGHT(N).
Aşadar, NUME'REVERSE_RANGE este un interval de variaţie
descrescător căruia nu i se cunosc decât valorile superioară şi inferioară.
Totuşi, se poate scrie:
PRENUME'REVERSE_RANGE este 1 to 8.
MEM'REVERSE_RANGE este 256 downto 1.
VIZ'REVERSE_RANGE (2) este 1024 downto 1.
BL'REVERSE_RANGE este 1 to 16.
CV'REVERSE_RANGE este 7 downto 0.
COD'REVERSE_RANGE este 1 to 3.
A'LENGTH[(N)]
Acest atribut returnează o valoare de tip întreg universal care
corespunde numărului de valori din cel de-al N-lea index al declaraţiei lui
A. N este o expresie statică de tip întreg universal a cărei valoare nu trebuie
să depăşească numărul de dimensiuni ale tabloului A. N este opţional, având
implicit valoarea 1. Prefixul A poate fi un obiect de tip tablou, sau un alias
de tablou sau un obiect de sub-tip constrâns de tip tablou. Dacă A este un
alias al unui obiect de tip tablou, valoarea returnată va fi extrasă din
declaraţia lui A şi nu din cea a obiectului.
De fapt, A'LENGTH(N) este egal cu A'HIGH(N) - A'LOW(N) + 1.
NUME'LENGTH este 10.
96 LIMBAJUL VHDL
PRENUME'LENGTH este 8.
MEM'LENGTH este 256.
VIZ'LENGTH (2) este 1024.
BL'LENGTH este 16.
CV'LENGTH este 8.
COD'LENGTH este 3.
A'ASCENDING[(N)]
Acest atribut returnează o valoare booleană, care este TRUE dacă cel
de-al N-lea index al tabloului A este crescător (to) şi FALSE în caz contrar
(downto). N este o expresie statică de tip întreg universal a cărei valoare nu
trebuie să depăşească numărul de dimensiuni ale tabloului A. N este
opţional, având implicit valoarea 1. Prefixul A poate fi un obiect de tip
tablou, sau un alias de tablou, sau un obiect de sub-tip constrâns de tip
tablou. Dacă A este un alias al unui obiect de tip tablou, valoarea returnată
va fi extrasă din declaraţia lui A şi nu din cea a obiectului.
NUME'ASCENDING este TRUE.
PRENUME'ASCENDING este FALSE.
MEM'ASCENDING este TRUE.
VIZ'ASCENDING (2) este TRUE.
BL'ASCENDING este FALSE.
CV'ASCENDING este TRUE.
COD'ASCENDING este TRUE.
a) Atribute semnal
S’DELAYED [(T)]
Acest atribut este un semnal identic cu S, dar întârziat cu T unităţi de
timp. T este deci o expresie statică pozitivă sau nulă de tipul fizic predefinit
TIME. Ea poate fi omisă, caz în care va lua valoarea 0 ns. Atenţie,
ATRIBUTE 97
S’DELAYED (0 ns) nu este identic cu S atunci când S tocmai şi-a schimbat
valoarea în acelaşi pas al simulării.
Fiind dat T un timp pozitiv sau nul, iar R – un semnal de acelaşi sub-
tip ca şi cel al semnalului S, dacă R şi S au aceleaşi valori iniţiale, atunci R
este identic cu S’DELAYED(T) oricare ar fi T.
Procesul echivalent ar putea fi următorul:
process(S)
begin
R <= transport S after T;
end process;
S’STABLE [(T)]
Acest atribut este un semnal de tip boolean. S este un semnal static.
T este o expresie statică pozitivă sau nulă de tipul fizic predefinit TIME. Ea
poate fi omisă, caz în care va lua valoarea 0 ns. Rezultatul este adevărat
dacă în decursul intervalului de timp T nu a apărut nici un eveniment pe
semnalul S şi fals în caz contrar.
Observaţii
S’STABLE(0 ns) este fals dacă S tocmai şi-a schimbat valoarea.
Aceasta se reduce la a afirma că dacă semnalul S întârziat cu 0 ns este egal
cu semnalul S, atunci S este stabil de 0 ns, ceea ce se scrie:
S’QUIET [(T)]
Acest atribut este un semnal de tip boolean. S este un semnal static.
T este o expresie statică pozitivă sau nulă de tipul fizic predefinit TIME. Ea
poate fi omisă, caz în care va lua valoarea 0 ns. Rezultatul este adevărat
dacă în decursul intervalului de timp T semnalul S „a rămas liniştit” (pe el
nu a apărut nici un eveniment şi nici o tranzacţie) şi este fals în caz contrar.
98 LIMBAJUL VHDL
Termenul „liniştit” a fost introdus aici pentru a traduce cuvântul QUIET; de
fapt, în contextul limbajului VHDL, el are o semnificaţie opusă termenului
ACTIV.
Pentru un ciclu de simulare dat, S’QUIET(0 ns) are valoarea TRUE
dacă şi numai dacă semnalul S este „liniştit” în decursul acestui ciclu de
simulare, adică dacă semnalul S nu se află pe lista semnalelor ai căror piloţi
(driver-e) sunt luate în considerare pentru ciclul de simulare curent.
S’TRANSACTION
Acest atribut este un semnal de tip predefinit BIT. Dacă S este
numele unui semnal static, acest atribut îşi schimbă valoarea (din ‘0’ devine
‘1’ şi invers) de fiecare dată când semnalul S devine activ în decursul unui
ciclu de simulare.
b) Atribute funcţie
S’EVENT
Acest atribut este o funcţie de tip boolean. Prefixul S identifică un
semnal static. Valoarea returnată de această funcţie este TRUE atunci când
tocmai a avut loc un eveniment pe semnalul S în decursul ciclului de
simulare.
Un eveniment este caracterizat de o schimbare a valorii unui semnal
activ. Pentru un semnal de tip compus, este suficient ca un eveniment să
aibă loc pe unul dintre sub-elementele sale pentru ca această funcţie atribut
să returneze valoarea TRUE.
S’ACTIVE
Acest atribut este o funcţie de tip boolean. S este numele unui
semnal static. Valoarea returnată de această funcţie este TRUE atunci când
semnalul S este activ în decursul ciclului de simulare şi FALSE în caz
contrar. Dacă semnalul este de tip compus, este suficient ca unul dintre sub-
elementele sale scalare să fie activ.
S’LAST_EVENT
Acest atribut este o funcţie care returnează o valoare de tipul
predefinit TIME. Prefixul S este numele unui semnal static. Valoarea
returnată de această funcţie reprezintă timpul scurs de la ultimul eveniment
survenit pe semnalul S.
ATRIBUTE 99
Pentru un semnal S compus, S’LAST_EVENT returnează valoarea
minimă a lui R’LAST_EVENT a fiecărui sub-element R al lui S.
S’LAST_ACTIVE
Acest atribut este o funcţie care returnează o valoare de tipul
predefinit TIME. Prefixul S este numele unui semnal static. Valoarea
returnată de această funcţie reprezintă timpul scurs din momentul în care
semnalul S a fost activ pentru ultima dată.
Pentru un semnal S compus, S’LAST_ACTIVE returnează valoarea
minimă a lui R’LAST_ ACTIVE a fiecărui sub-element R al lui S.
S’LAST_VALUE
Acest atribut este o funcţie care returnează o valoare de tipul
semnalului S. Prefixul S este numele unui semnal static. Valoarea returnată
de această funcţie este cea a semnalului S imediat înaintea ultimei
modificări a lui S.
Pentru un semnal S de tip scalar, S’LAST_VALUE este egal cu
S’DELAYED(T), unde T este de tip TIME, este ≥ 0 ns şi ia valoarea cea
mai mică astfel încât S’STABLE(T) să fie FALSE. Dacă o asemenea
valoare de timp nu există, S’LAST_VALUE returnează valoarea semnalului
S.
S’DRIVING_VALUE şi S’DRIVING
Aceste două atribute sunt funcţii şi sunt oarecum diferite de cele
precedente datorită modului lor de utilizare. Ele au fost introduse pentru a se
evita necesitatea de a citi valoarea unui port de ieşire (a unui port de mod
out).
S <= A and B;
NS<= not S;
S <= A and B;
NS<= not S'DRIVING_VALUE;
ATRIBUTE 101
Atributul S'DRIVING este mai puţin folosit. Într-adevăr, în cazul în
care, în mod dinamic, nu se ştie dacă semnalul S este deconectat sau nu,
următoarea porţiune de cod permite evitarea unei erori:
if S'DRIVING then
V := S'DRIVING_VALUE;
end if;
X'SIMPLE_NAME
Acest atribut returnează, sub forma unui şir de caractere, numele X.
Astfel, dacă SIG este un semnal, SIG'SIMPLE_NAME va returna şirul de
caractere "sig".
X'PATH_NAME
Acest atribut returnează un şir de caractere care, pe lângă numele X,
conţine şi suita de etichete care permite revenirea, de-a lungul structurii
descrierii date de către proiectant, până la X: etichete de blocuri, de instanţe
de componente etc.
X'INSTANCE_NAME
Acest atribut amestecă informaţiile structurale oferite de
PATH_NAME cu alte informaţi relative la configuraţie (numele entităţii,
numele arhitecturii, numele configuraţiei etc.)
102 LIMBAJUL VHDL
2.3 Atribute definite de către proiectant
type IMPLEMENTARE is
record
NUMĂR_FIR: INTEGER;
NUMĂR_PLACĂ: INTEGER;
end record;
attribute LOCALIZARE: IMPLEMENTARE;
attribute NUMĂR_MULŢIME: INTEGER;
type CAPACITY is range 0 to 1E15
units
ff; -- femtofarad
pf = 1000 ff; -- picofarad
nf = 1000 pf; -- nanofarad
uf = 1000 nf; -- microfarad
mf = 1000 uf; -- milifarad
end units;
attribute CAPACITATE: CAPACITY;
others: clasă_element
all: clasă_element
obiect_la_care_se_referă'nume_atribut
3. Desfăşurarea lucrării
3.1 Se vor testa toate atributele prezentate pe cadrul de exemple din
lucrare. Se vor utiliza atributele predefinite pentru descrierea
comportamentului unui bistabil JK Master-Slave.
3.2 Se va defini atributul NUMĂR_APARIŢII care să acţioneze
asupra unui obiect de tip TIME.
3.3 Se va testa următorul exemplu de utilizare a atributului
LAST_EVENT:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity BISTABIL_D is
generic(SETUP_TIME: TIME:= 1 ns; HOLD_TIME: TIME:= 2 ns);
port(D, CLK: in STD_LOGIC;
Q: out STD_LOGIC);
begin -- Verificarea respectării timpului de prepoziţionare (set-up)
VERIF_SETUP: process(CLK)
begin
if (CLK = ‘1’) and (CLK’EVENT) then
assert (D’LAST_EVENT >= SETUP_TIME)
report “Încălcarea condiţiei de timp de set-up” severity ERROR;
end if;
end process VERIF_SETUP;
end BISTABIL_D;
1. Scopul lucrării
2. Consideraţii teoretice
2.1 Procese
Instrucţiunea_1 Instrucţiunea_1
NU DA
În VHDL toate
instrucţiunile sunt
Instrucţiunea_2 executate secvenţial Instrucţiunea_2
într-o buclă infinită
Instrucţiunea_3 Instrucţiunea_3
process Instrucţiunea_1
begin
Instrucţiunea_1;
Instrucţiunea_2;
Instrucţiunea_3;
Instrucţiunea_2
wait <condiţie>;
end process;
Dispozitivul reia
operaţiile
Instrucţiunea_3
Dispozitivul suspendă
operaţiile
Condiţie DA
îndeplinită
NU
Instrucţiunea_1
Instrucţiunea_2
Figura 6.3 Execuţia unui proces care conţine mai multe instrucţiuni wait
Observaţie
Instrucţiunea wait until condiţie suspendă procesul până când
respectiva condiţie DEVINE adevărată datorită unei MODIFICĂRI a
oricărui semnal dintre cele care participă la formarea condiţiei. Trebuie
subliniată diferenţa dintre termenii „devine” şi „se modifică”: dacă un
semnal rămâne neschimbat, instrucţiunea wait until nu va reactiva procesul,
chiar dacă se îndeplineşte condiţia!
proc2: process
begin
wait on SIG1, SIG2 until CLOCK = '1';
...
end process proc2;
process
begin
wait on SIGA;
Instrucţiunea1;
Instrucţiunea2;
Instrucţiunea3;
end process;
process
begin
Instrucţiunea1;
Instrucţiunea2;
Instrucţiunea3;
wait on SIGB;
end process;
Observaţii
Datorită regulilor de execuţie a proceselor (descrise anterior), o
instrucţiune wait on plasată la începutul procesului NU este echivalentă cu
un proces cu listă de sensibilitate, chiar dacă semnalele din lista de
sensibilitate a procesului sunt aceleaşi cu cele care ar apărea în lista de
sensibilitate a instrucţiunii wait on.
Un proces înzestrat cu listă de sensibilitate nu poate să conţină nici o
altă instrucţiune wait explicită.
Observaţie
„Toate instrucţiunile” înseamnă într-adevăr toate instrucţiunile din
cadrul procesului, nu numai cele legate de semnalul care a reactivat
procesul!
S1
S2
0 ns 10 ns + 1 delta
0 ns + 1 delta 10 ns
În aceste două momente de
timp, semnalele au valori egale!
Figura 6.4 Întârzierile „delta” provoacă alarme false
signal A, B, C, X, Y, Z: INTEGER;
process (A, B, C)
begin
X <= A + 1;
Y <= A * B;
Z <= C - X;
B <= Z * C;
Y <= B;
end process;
118 LIMBAJUL VHDL
Atunci când procesul va fi activat de o modificare a valorii
semnalului C, aceasta va provoca o modificare a valorii semnalului B din
interiorul procesului. Acest eveniment survenit pe semnalul B va provoca la
rândul lui o nouă reactivare a procesului, deoarece semnalul B face parte din
lista de sensibilitate a procesului.
La execuţia acestui proces, asignările de semnale sunt efectuate
secvenţial, în ordine, însă cea de-a doua asignare (Y <= A * B;) nu va fi
executată niciodată deoarece se va activa numai ultima asignare a
semnalului Y. Mai mult, în cea de-a treia asignare (Z <= C - X;) va fi
folosită numai valoarea anterioară a lui X, deoarece prima asignare (X <= A
+ 1;) va avea efectiv loc numai la suspendarea procesului, adică după
parcurgerea integrală şi efectuarea tuturor instrucţiunilor din lista de
instrucţiuni secvenţiale.
Restricţiile impuse asupra semnalelor au un impact deosebit de
puternic asupra aplicaţiilor lor practice. Imposibilitatea de a declara semnale
în cadrul proceselor nu constituie o problemă majoră, însă regulile de
asignare de valori semnalelor au consecinţe dintre cele mai serioase.
De vreme ce semnalele pot stoca numai ultima lor valoare asignată,
ele nu pot fi utilizate pentru stocarea datelor temporare sau intermediare în
interiorul proceselor.
Un alt inconvenient major îl constituie faptul că noile valori le sunt
asignate semnalelor nu în cadrul execuţiei instrucţiunilor de asignare, ci doar
după suspendarea procesului. Aceasta face ca analiza proiectului să devină
destul de dificilă, aşa cum se poate vedea din exemplul prezentat mai jos.
signal A, B, C, D, E: INTEGER;
process (C, D)
begin
A <= 2; -- Instrucţiunea 1
B <= A + C; -- Instrucţiunea 2
A <= D + 1; -- Instrucţiunea 3
E <= A * 2; -- Instrucţiunea 4
end process;
entity E1 is
port (A: in NATURAL := 1;
B : inout NATURAL := 1);
end entity E1;
architecture ARH1 of E1 is
begin
P1: process (A)
begin
B <= A + 2;
B <= B + 3;
B <= B * 2;
B <= B + 1; -- Numai această ultimă asignare are loc
end process P1;
end architecture ARH1;
-- Rezolvarea problemei prin introducerea de variabile
architecture ARH2 of E1 is
begin
P2: process (A)
variable B_VAR: NATURAL;
begin
B_VAR := A + 2;
B_VAR := B_VAR + 3;
B_VAR := B_VAR * 2;
B <= B_VAR + 1;
end process P2;
end architecture ARH2;
variable X, Y: REAL;
variable A, B: BIT_VECTOR (0 to 7);
-- Variabile cu nume simple
X := 108.0;
A := B;
A := "11110000";
-- Variabile cu nume parţiale
A(3 to 6) := ('1', '1', '1', '1');
A(0 to 5) := B(2 to 7);
-- Variabile cu nume indexate
A(7) := '0';
B(0) := A(6);
3. Desfăşurarea lucrării
1. Scopul lucrării
Lucrarea prezintă pe larg toate instrucţiunile secvenţiale permise în
cadrul domeniului secvenţial: instrucţiunea assert, instrucţiunea report,
instrucţiunea de asignare de valori semnalelor, apelul secvenţial de
procedură, structura condiţională if-then-else, instrucţiunea case, structura
de buclă loop, instrucţiunea next, instrucţiunea exit, instrucţiunea return şi
instrucţiunea nulă. Pentru toate instrucţiunile se pune la dispoziţie sintaxa
lor completă, însoţită de exemple semnificative.
2. Consideraţii teoretice
2.1 Instrucţiunea assert
report "Salut!";
INSTRUCŢIUNI SECVENŢIALE 127
este echivalentă cu:
VAR1 := 7;
VAR2 := VAR1 / (VAR1 + 22);
-- Zona declarativă
variable X: INTEGER := 7;
variable Y: REAL := RADICAL(X);
-- Presupunem că RADICAL este o funcţie definită anterior
-- care returnează un rezultat de tip REAL
-- Zona declarativă
type P_POANTOR is acces INTEGER; -- Declaraţia unui tip acces
-- care poantează spre un obiect de tip întreg
variable UN_POANTOR: P_POANTOR;
begin
UN_POANTOR := new INTEGER (3);
-- S-a creat un obiect întreg iniţializat cu valoarea 3.
-- Tipul acces care poantează la acest întreg este stocat în
-- variabila UN_POANTOR.
end;
Observaţie
Instrucţiunea new „consumă” spaţiu de memorie deoarece ea creează
un obiect. La crearea fiecărui tip acces, se creează implicit o procedură
DEALLOCATE (a se vedea lucrarea nr. 4) care permite recuperarea
spaţiului de memorie ocupat de către obiectele de acest tip.
if Condiţie_booleană then
Secvenţa_de_instrucţiuni_1
else
Secvenţa_de_instrucţiuni_2
end if;
if A>B then
...
-- Secvenţa_de_instrucţiuni_1
...
else
if A=B then
...
-- Secvenţa_de_instrucţiuni_2
...
else
...
-- Secvenţa_de_instrucţiuni_3
...
end if;
end if;
if A>B then
...
-- Secvenţa_de_instrucţiuni_1
...
elsif A=B then
...
-- Secvenţa_de_instrucţiuni_2
...
else
...
-- Secvenţa_de_instrucţiuni_3
...
end if;
INSTRUCŢIUNI SECVENŢIALE 131
2.6 Instrucţiunea case
case expresie is
when Valoare_1 =>... -- Secv_instrucţiuni_1
when Val_2|Val_3|Val_4 => ... -- Secv_instrucţiuni_2
when Val_5 to Val_6 =>... -- Secv_instrucţiuni_3
...
when others =>... -- Secv_instrucţiuni_n
end case;
variable N: INTEGER;
...
loop
N := N + 1;
end loop;
De exemplu:
variable R, M, N: INTEGER;
...
while R /= 0 loop
R := M mod N;
M := N;
N := R;
end loop;
next {eticheta_buclei};
- condiţională:
exit {eticheta_buclei};
- condiţională.
În acest ultim caz, ieşirea din buclă nu are loc decât dacă respectiva
condiţie este adevărată.
La fel ca în cazul instrucţiunii next, această instrucţiune, dacă nu are
specificată o etichetă, nu se referă decât la bucla de nivelul cel mai de jos
care o înglobează. Dacă prezintă o etichetă, atunci instrucţiunea exit permite
ieşirea din bucla care poartă aceeaşi etichetă.
Iată un exemplu de utilizare a instrucţiunii exit:
variable R, M, N: INTEGER;
...
loop
R := M mod N;
M := N;
N := R;
exit when R = 0;
end loop;
return VALOARE;
INSTRUCŢIUNI SECVENŢIALE 135
Tipul lui VALOARE trebuie, bineînţeles, să fie cel declarat în
specificaţia funcţiei. Într-o funcţie pot exista mai multe instrucţiuni return
pentru că pot exista mai multe ramuri de decizie.
Instrucţiunea return poate fi utilizată pentru întreruperea cursului
unei funcţii şi pentru a reveni în programul apelant. În acest caz, nu trebuie
să i se asocieze nici o valoare.
return;
null;
3. Desfăşurarea lucrării
3.1 Se va implementa exemplul prezentat în continuare, care
gestionează traficul la o trecere simplă de pietoni. Dacă există
erori în descriere, acestea se vor detecta şi corecta.
136 LIMBAJUL VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.all
entity SEMAFOR is
port(
CLOCK, RESET, SENZOR1, SENZOR2: in STD_LOGIC;
ROSU1, ROSU2, GALBEN1, GALBEN2, VERDE1, VERDE2: out STD_LOGIC;
);
end SEMAFOR;
NUMĂRĂTOR: process
variable COUNT: INTEGER := 0;
begin
wait until CLK = ‘1’;
while LEVEL = ‘1’ loop COUNT := COUNT + 1;
wait until CLK = ‘0’;
end loop;
end process NUMĂRĂTOR;
LUCRAREA NR. 8
DOMENIUL CONCURENT
1. Scopul lucrării
2. Noţiuni introductive
Unitate
de Hard disc
dischetă
entity BIST_D is
port (M, D: in BIT;
Q, NQ: buffer BIT);
end BIST_D;
entity SUMATOR_COMPLET is
port (A, B, CARRY_IN: in BIT;
SUM, CARRY_OUT: out BIT);
end SUMATOR_COMPLET ;
architecture ARH1 of SUMATOR_COMPLET is
signal S1, S2, S3, S4: BIT;
begin
P1: process(B, CARRY_IN)
begin
S1 <= B xor CARRY_IN;
end process P1;
P2: process(B, CARRY_IN)
begin
S2 <= B and CARRY_IN;
end process P2;
P3: process(A, B)
begin
S3 <= A and B;
end process P3;
P4: process(A, CARRY_IN)
begin
S4 <= A and CARRY_IN;
end process P4;
P5: process(A, S1)
begin
SUM <= A xor S1;
end process P5;
P6: process(S2, S3, S4)
begin
CARRY_OUT <= S2 or S3 or S4;
end process P6;
end architecture ARH1;
142 LIMBAJUL VHDL
După cum s-a prezentat deja în lucrarea nr. 6, un proces suspendat va
fi reactivat atunci când oricare dintre semnalele de pe lista sa de sensibilitate
îşi modifică valoarea. Această regulă se aplică şi în cazul în care există mai
multe procese într-o arhitectură: atunci când un semnal îşi modifică
valoarea, toate procesele care au respectivul semnal în lista lor de
sensibilitate vor fi reactivate. Instrucţiunile din interiorul proceselor
reactivate vor fi aşadar executate secvenţial, în ordine. Subliniem însă că
aceste instrucţiuni vor fi executate independent de instrucţiunile aflate în
interiorul celorlalte procese.
Conceptul de concurenţă ar fi probabil mult mai uşor de înţeles dacă
am putea scrie procesele unul lângă celălalt, şi nu unul după celălalt, aşa
cum suntem obligaţi să o facem în fişierul sursă, pe orice sistem de calcul
existent în momentul de faţă.
Întrucât procesele nu fac deosebirea între semnalele generate extern
(provenite din mediul exterior) şi cele generate intern (declarate în interiorul
arhitecturii), rezultă că semnalele care activează procesele pot fi generate şi
de către alte procese existente în interiorul aceleiaşi arhitecturi.
De fiecare dată când un semnal aflat pe lista de sensibilitate a unui
anumit proces îşi modifică valoarea, procesul respectiv va fi activat. Acest
lucru se întâmplă indiferent dacă modificarea valorii semnalului a fost
produsă de către mediul exterior sau de către un alt proces.
Observaţie
Pentru a realiza transferuri de informaţie între procese nu se pot
utiliza decât semnale. Datorită faptului că variabilele sunt obiecte locale
proceselor, ele nu pot fi utilizate ca purtătoare de informaţie între procese.
entity BIST_JK is
port (J, K: in BIT;
Q, NQ: buffer BIT);
end BIST_JK;
architecture ARH of BIST_JK is
signal S1, S2, S3, S4, CLOCK: BIT;
begin
CLK: process -- Generatorul de semnal de tact
begin
CLOCK <= '0';
wait for 5 ns;
CLOCK <= '1';
wait for 5 ns;
end process CLK;
NAND1: process(J, NQ)
begin
S1 <= J nand NQ;
end process NAND1;
NAND2: process(S1, S4)
begin
S2 <= S1 nand S4;
end process NAND2;
NAND3: process(S3, Q)
begin
S4 <= S3 nand Q;
end process NAND3;
NOT1: process(K)
begin
S3 <= not(K);
end process NOT1;
process(CLOCK)
begin
if CLOCK = '1' then
Q <= S2;
NQ <= not(S2);
end if;
end process;
end architecture ARH;
Observaţie
Instrucţiunile de asignare concurentă a semnalelor sunt echivalente
cu un proces conţinând o singură instrucţiune de asignare de semnal. Dacă
în cadrul unui proces apar două sau mai multe instrucţiuni de asignare, ele
vor fi executate într-o anumită secvenţă predefinită. Cu toate acestea, dacă
aceleaşi instrucţiuni vor apărea ca asignări concurente de semnal (deci apar
în afara oricărui proces), ele vor fi executate concurent.
entity BIST_RS is
port (SET, RESET: in BIT;
Q, NQ: buffer BIT);
end BIST_RS;
architecture ARH of BIST_RS is
begin
Q <= not(NQ and SET) after 1 ns;
NQ <= not(Q and RESET) after 1 ns;
end architecture ARH;
DOMENIUL CONCURENT 145
entity SUMATOR_COMPLET is
port (A, B, CARRY_IN: in BIT;
SUM, CARRY_OUT: out BIT);
end SUMATOR_COMPLET;
architecture ARH2 of SUMATOR_COMPLET is
signal S1, S2, S3, S4: BIT;
begin
S1 <= B xor CARRY_IN;
S2 <= B and CARRY_IN;
S3 <= A and B;
S4 <= A and CARRY_IN;
SUM <= A xor S1;
CARRY_OUT <= S2 or S3 or S4;
end architecture ARH2;
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity SISTEM is
port (INSTR: in INTEGER range 0 to 4; -- codul instrucţiunii
DATA_BUS: inout STD_LOGIC_VECTOR(7 downto 0));
end SISTEM;
148 LIMBAJUL VHDL
architecture ARH of SISTEM is
signal CIT_SCR: STD_LOGIC; -- '1' = citire, '0' = scriere
signal SELECT_DISP: STD_LOGIC;
-- '1' memoria, '0' interfaţa de I/E
begin
CTRL: process(INSTR) -- Procesul de control
begin
case INSTR is
when 0 => CIT_SCR <= '1'; -- Instrucţiune de citire
SELECT_DISP <= '1'; -- din memorie
when 1 => CIT_SCR <= '0'; -- Instrucţiune de scriere
SELECT_DISP <= '1'; -- în memorie
when 2 => CIT_SCR <= '1'; -- Instrucţiune de citire
SELECT_DISP <= '0'; -- din dispozitivul de I/E
when 3 => CIT_SCR <= '0'; -- Instrucţiune de scriere
SELECT_DISP <= '0'; -- în dispozitivul de I/E
when 4 => CIT_SCR <= 'Z'; -- Instrucţiune nulă
SELECT_DISP <= 'Z';
end case;
end process CTRL;
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity PILOŢI1 is
port (A, S: in STD_LOGIC;
Y: out STD_LOGIC);
end PILOŢI1;
150 LIMBAJUL VHDL
architecture ARH1 of PILOŢI1 is
begin
P1: process(A, S)
begin
if S = '1' then Y <= A;
else Y <= 'Z';
end if;
end process P1;
P2: process(A, S)
begin
if S = '0' then Y <= not(A);
else Y <= 'Z';
end if;
end process P2;
end architecture ARH1;
Studiind cu mai multă atenţie această problemă, ne putem da seama
că funcţia de rezoluţie are nevoie de mai multe valori decât cele din
componenţa setului de bază. O situaţie similară apare atunci când încercăm
să reprezentăm semnale multi-sursă în VHDL. De exemplu, pentru tipul
BIT, prima problemă care se pune este următoarea: ce se va întâmpla dacă
vom mixa valorile '0' şi '1' (cu alte cuvinte, care este valoarea rezolvată
pentru '0' şi '1'?). Problema nu poate fi rezolvată folosind numai două valori
– prin urmare, întrebarea precedentă nu are răspuns.
Acest aspect are o serie întreagă de consecinţe: dacă vom folosi
numai tipurile de date BIT şi BIT_VECTOR, atunci NU vom putea specifica
un microprocesor (de exemplu) în VHDL. Tipurile de date nerezolvate (aşa
cum sunt cele două tipuri menţionate mai sus, BIT şi BIT_VECTOR) nu pot
fi folosite pentru semnale multi-sursă, care sunt însă indispensabile pentru
specificarea magistralelor de date (care există, în mod evident, în orice
microprocesor). Pentru rezolvarea acestei probleme, trebuie să utilizăm alt
tip de date, care să conţină mai mult de două valori şi care să aibă definită o
funcţie de rezoluţie pentru toate combinaţiile valorilor semnalelor.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity PILOŢI2 is
port (A: in BIT;
Y: out BIT;
B: in STD_LOGIC;
Y1: out STD_LOGIC);
end PILOŢI2;
DOMENIUL CONCURENT 151
architecture ARH2 of PILOŢI2 is
begin
P1: process(A)
begin -- Această condiţie este suficientă pentru detectarea
-- frontului ascendent în cazul tipului BIT
if A = '1' and A'EVENT then Y <= A after 1 ns;
end if;
end process P1;
P2: process(B)
begin -- Această condiţie este suficientă pentru detectarea
-- frontului ascendent în cazul tipului STD_LOGIC
if B = '1' and B'EVENT and B'LAST_VALUE = '0'
then Y1 <= B after 2 ns;
end if;
end process P2;
end architecture ARH2;
Observaţie
O funcţie de rezoluţie trebuie în principiu să fie comutativă şi
asociativă, dacă se urmăreşte modelarea corectă a unui conflict de valoare.
Dacă nu se doreşte aşa ceva, atunci ordinea apelurilor, care nu se află sub
controlul proiectantului, va influenţa valoarea rezultantă a unui conflict. Cu
toate acestea, aceste proprietăţi (comutativitatea şi asociativitatea) nu fac
obiectul unor verificări din partea compilatorului.
Al doilea exemplu este de fapt un extras din codul sursă original din
pachetul IEEE STD_LOGIC şi reprezintă funcţia şi tabelul de rezoluţie
pentru tipul de date STD_LOGIC. Aceasta este cea mai simplă modalitate
de reprezentare a funcţiei de rezoluţie pentru logica cu 9 valori:
VALID_B
Figura 8.4 Circuit a cărui ieşire este controlată de doi piloţi independenţi
În circuitul din figura 8.4, ieşirea Y este controlată din două surse
independente. Specificaţia sa în VHDL este prezentată mai jos:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity PILOŢI3 is
port (VALID_A, VALID_B: in BOOLEAN;
A, B: in STD_LOGIC;
Y: out STD_LOGIC);
end PILOŢI3;
156 LIMBAJUL VHDL
architecture ARH3 of PILOŢI3 is
signal SA, SB: STD_LOGIC;
begin
SA <= A when VALID_A else 'Z';
SB <= B when VALID_B else 'Z';
P1: process(SA)
begin
Y <= SA;
end process P1;
P2: process(SB)
begin
Y <= SB;
end process P2;
end architecture ARH2;
3. Desfăşurarea lucrării
1. Scopul lucrării
2. Consideraţii teoretice
CLOCK
Valoarea expresiei A
Observaţie
Atributul STABLE returnează valoarea booleană TRUE atunci când
semnalul vizat nu şi-a modificat valoarea în pasul curent al simulării.
Condiţia de mai sus înseamnă deci că semnalul de tact are valoarea '1' şi nu
este stabilă (tocmai s-a modificat) în pasul curent al simulării. Atributul
STABLE este prezentat în detaliu în lucrarea nr. 5.
BLOC2: block
signal GUARD: BOOLEAN;
begin
GUARD <= CLOCK = '1' and not CLOCK'STABLE;
S1 <= DATA1 after 10 ns when GUARD else S1;
S2 <= DATA2 after 15 ns when GUARD else S2;
end block BLOC2;
package PAC is
procedure CHECKTIMING (signal A, B: BIT; T: TIME);
end PAC;
component COMP
port (A, B: inout BIT);
end component;
for C: COMP use entity X(Y) port map (P1 => A, P2 => B);
VERIF1: process
begin
VERIF_SETUP(A, B, TS);
wait on A, B;
end process VERIF1;
{etichetă:} process
begin
assert condiţie {report mesaj}{severity nivel_de_eroare};
wait on lista_semnalelor_care_apar_în_condiţie;
end process {etichetă};
Observaţie
Este important de reţinut că acest proces echivalent nu are listă de
sensibilitate, ci conţine o instrucţiune secvenţială wait după instrucţiunea
secvenţială assert. Prin urmare, chiar dacă lista semnalelor care apar în
condiţie este vidă, procesul nu se va putea repeta în buclă.
Observaţie
Scrierea procesului echivalent al acestei instrucţiuni ascunde o
capcană! În cazul în care condiţia nu depinde de nici un semnal, lista
semnalelor care intervin în cadrul condiţiei este vidă şi aceasta va fi
verificată doar o singură dată, la iniţializare, şi niciodată după aceea.
De exemplu, prin utilizarea condiţiei NOW < TIMP_MAX (unde
TIMP_MAX este o constantă şi NOW este funcţia care returnează timpul
curent al simulării), nu vom ajunge niciodată la sfârşitul simulării.
Dacă dorim să testăm o condiţie care nu utilizează nici un semnal,
atunci vom fi nevoiţi să scriem un proces care va conţine instrucţiunea
secvenţială assert şi va avea o listă de sensibilitate adecvată.
if condiţie_booleană_1 then
nume_sau_agregat <= {transport} formă_de_undă_1;
elsif condiţie_booleană_2 then
nume_sau_agregat <= {transport} formă_de_undă_2;
...
else
nume_sau_agregat <= {transport} formă_de_undă_n;
end if;
Această formă se numeşte forma condiţională echivalentă.
168 LIMBAJUL VHDL
Sintaxa formei selective este următoarea:
case expresie is
when alegere_1 =>
nume_sau_agregat <= {transport} formă_de_undă_1;
when alegere_2 =>
nume_sau_agregat <= {transport} formă_de_undă_2;
...
when alegere_n =>
nume_sau_agregat <= {transport} formă_de_undă_n;
end case;
if GUARD then
formă echivalentă (condiţională sau selectivă)
end if;
if GUARD then
formă echivalentă (condiţională sau selectivă)
else
instrucţiune de deconectare
end if;
Observaţie
O arhitectură este un bloc (fără condiţie de gardă). Într-un bloc fără
condiţie de gardă putem însă declara un semnal GUARD şi apoi putem
folosi instrucţiuni gardate. Aşadar, exemplul de mai jos este perfect valabil:
2.6.1 Instanţierea
A instanţia o componentă înseamnă a face o copie (o instanţă) a unei
componente deja declarate („modelul”) şi de a o personaliza pentru a da curs
unei necesităţi particulare. De exemplu, dacă am declarat deja o componentă
INVERSOR, atunci putem instanţia o componentă INV1, apoi o
componentă INV2 etc. Sintaxa instrucţiunii este următoarea:
etichetă: numele_componentei_model
{corespondenţa parametrilor generici}
{corespondenţa porturi efective / porturi locale modelului};
INSTRUCŢIUNI CONCURENTE 171
Această instrucţiune permite descrierea unui modul al circuitului ca
fiind o instanţă a unui model. Modelul este definit printr-o declaraţie de
componentă. Se pot preciza următoarele informaţii:
- Valoarea parametrilor generici ai componentei. Acest aspect
reprezintă adaptarea componentei la nevoile de modelare
curente;
- Corespondenţa dintre porturile formale ale componentei model
şi porturile efective, cele pe care le vom conecta în circuitul
nostru actual. Există posibilitatea de a nu conecta toate porturile
modelului, caz în care porturile efective corespunzătoare nu vor
exista (vor fi „în aer”). În cazul porturilor de intrare (de mod in),
acestora li se vor asigna valorile implicite prevăzute eventual
pentru ele.
În exemplul de mai jos, se obţin două componente, C1 şi C2, care
asigură interconectarea semnalelor A, B, C şi D de tip BIT.
signal A, B, C, D: BIT;
-- Forma condiţională
etichetă: if condiţie_booleană generate
...
Secvenţă de instrucţiuni concurente
...
end generate {etichetă};
-- Forma iterativă
etich: for nume_param_generare in interval_discret generate
...
Secvenţă de instrucţiuni concurente
...
end generate {etich};
Intrare-lanţ Ieşire-lanţ
entity LANŢ_DE_INVERSOARE is
generic (N: INTEGER);
port (INTRARE_LANŢ: in BIT; IEŞIRE_LANŢ: out BIT);
end LANŢ_DE_INVERSOARE;
3. Desfăşurarea lucrării
1. Scopul lucrării
2. Consideraţii teoretice
Observaţie
O excepţie la această regulă o constituie funcţia NOW care
returnează data curentă a simulării şi care nu are parametri. Această funcţie
se numeşte impură.
Antet_sub-program is
{zona declarativă} --Acoladele delimitează părţile opţionale
begin
{zona rezervată instrucţiunilor}
end {nume_sub-program}
-- Procedura MIN
MIN (VAR, 5, REZULTAT); -- Apel poziţional
MIN (A => VAR, B => 5, C => REZULTAT); -- Apel prin denumire
MIN (B => 5, C => REZULTAT, A => VAR); -- Apel prin denumire
-- Funcţia MIN
REZULTAT := MIN(VAR, 5); -- Apel poziţional
REZULTAT := MIN(A => VAR, B => 5); -- Apel prin denumire
2.5 Supraîncărcarea
Observaţie
Anumite informaţii conţinute în specificaţia unui sub-program, cum
ar fi numele parametrilor formali, modul lor de transmitere, clasa lor sau
valoarea lor implicită nu fac parte din profilul sub-programului. Două sub-
programe care nu diferă decât prin una sau mai multe dintre aceste
informaţii vor provoca o ambiguitate care va fi semnalată de către
compilator. Prin urmare, următoarele două funcţii nu se vor supraîncărca (se
va genera o eroare la compilare, deoarece simbolul MIN este definit de două
ori):
A and B
2.6.1 Recursivitatea
În VHDL există posibilitatea de a scrie programe recursive. Într-un
limbaj de programare clasic, în general vorbind, recursivitatea reprezintă
proprietatea unui sub-program de a se putea apela pe el însuşi. În VHDL este
permisă şi recursivitatea încrucişată (sub-programul A apelează sub-
programul B, care la rândul său apelează sub-programul A). În cazul
aplicării recursivităţii, trebuie să ne asigurăm că am scris o instrucţiune de
test pentru stoparea sa.
Astfel, este posibil să descriem un sumator complet pe N biţi în
funcţie de el însuşi, instanţiat pe N-1 biţi, şi a unui modul de un singur bit
care va avea rolul de test de stopare a recursivităţii.
Trebuie însă să avem în vedere că, în VHDL, scopul final îl
reprezintă în general obţinerea unei structuri hardware. De aceea, este bine
să ne punem mereu întrebarea: la ce ne ajută acest gen de descriere? Va
exista oare o realitate materială (hardware) corespunzătoare? În acest caz,
răspunsul este din păcate negativ…
2.6.1 Vizibilitatea
În figura 10.2 sunt prezentate regulile de vizibilitate a sub-
programelor în VHDL:
186 LIMBAJUL VHDL
Apelant
(pachet, proces, bloc sau alt sub-program)
Procedura A
Declaraţii
globale Declaraţii locale
(locale procedurii A
apelantului) Procedura B
Declaraţii locale
procedurii B
3. Desfăşurarea lucrării
1. Scopul lucrării
2. Consideraţii teoretice
...
-- Constantă declarată în arhitectura modulului de simulare
constant CONSTANTA_TACT: TIME := 20 ns;
signal CLOCK: STD_LOGIC;
...
-- Perioada tactului va fi de: 2*CONSTANTA_TACT = 40 ns;
GENERATOR_TACT: process(CLOCK)
begin
if CLOCK = 'U' then CLOCK <= '0';
else
CLOCK <= not CLOCK after CONSTANTA_TACT;
end if;
end process GENERATOR_TACT;
Noţiunile expuse până în acest punct sunt reluate într-o formă grafică
în figura 11.1.
PROIECTARE
VERIFICARE
Specificarea modulului de simulare se
Definirea stimulilor poate face numai după specificarea
stimulilor. Acest modul conţine stimulii şi
o instanţă a sistemului proiectat (numit
UST – unitate supusă testării). În faza de
Specificarea modulului verificare se va simula acest modul şi NU
de simulare unitatea supusă testării.
Simularea modulului de
simulare
begin
-- Instanţierea unităţii supuse testării (UST)
UST: COMP_D port map (...);
-- Definirea stimulilor
GENERATOR_TACT: process
begin
if not END_SIM then
CLK <= '0';
wait for PERIOADA_CLK / 2;
CLK <= '1';
wait for PERIOADA_CLK / 2;
else wait;
end if;
end process GENERATOR_TACT;
-- Stimulul asignat porturilor de intrare ale COMP_D
STIMUL: process
begin
D <= '1';
wait for 200 ns;
D <= '0';
wait for 200 ns;
END_SIM := TRUE; -- când END_SIM devine TRUE, procesul
-- GENERATOR_TACT este oprit
wait;
end process STIMUL;
end ARH_MS_BISTABIL_D ;
entity DMUX is
port(X: in BIT;
S: in BIT_VECTOR (1 downto 0);
Y: out BIT_VECTOR (3 downto 0));
end DMUX;
architecture ARH_DMUX of DMUX is
begin
Y <= ('0', '0', '0', X) when S = "00" else
('0', '0', X, '0') when S = "01" else
('0', X, '0', '0') when S = "10" else
(X, '0', '0', '0') when S = "11";
end ARH_DMUX;
-- Entitatea modulului de simulare
entity MS_DMUX is
end MS_DMUX;
2.3.3 Stimuli
Un element esenţial al oricărui modul de simulare îl reprezintă setul
de stimuli: o secvenţă de valori aplicate în timp fiecărui semnal de intrare al
unităţii supuse testării. De vreme ce modulul de simulare nu comunică cu
mediul său înconjurător prin semnale, toţi stimulii trebuie să fie declaraţi
intern în arhitectura modulului de simulare. Ei vor fi declaraţi la fel ca
oricare alt semnal, în zona declarativă a arhitecturii.
Stimulii pot fi specificaţi astfel:
- ca instrucţiuni concurente de asignare de valori unor semnale (în
care modificările survenite pe semnalele de intrare sunt date ca
forme de undă, cu ajutorul cuvântului cheie after şi alegând
modelul de propagare dorit, transport sau inerţial);
- în interiorul unui proces care conţine instrucţiuni de asignare de
valori unor semnale separate prin intermediul instrucţiunilor wait
for (care introduc întârzieri între execuţia instrucţiunilor de
asignare menţionate mai sus). În acest caz, este necesară
adăugarea unei instrucţiuni wait vide (fără nici o condiţie) pe
ultima poziţie a listei de instrucţiuni secvenţiale executate în
cadrul procesului. Această instrucţiune va suspenda procesul pe
termen nelimitat (altminteri - aşa cum am arătat în lucrarea nr. 6
dedicată proceselor - procesul ar fi executat din nou de la
început).
196 LIMBAJUL VHDL
Relaţia dintre stimuli şi unitatea supusă testării este specificată prin
intermediul asignărilor realizate în cadrul clauzei port map a instrucţiunii
de instanţiere a unităţii testate.
Se prezintă în continuare exemplul unui modul de simulare al unui
numărător pe 8 biţi, în care stimulii sunt specificaţi atât în formă secvenţială
cât şi în formă concurentă:
STIM2: process
begin
DIR <= '1'; -- Numărare jos
CE <= '1'; -- Clock Enable permite funcţionarea
wait for 2 us;
DIR <= '0'; -- Numărare sus
wait for 1 us;
CE <= '0'; -- Clock Enable nu permite funcţionarea
DIR <= '1'; -- Numărare jos
wait for 1 us;
DIR <= '0'; -- Se reia Numărarea crescătoare
wait;
end process STIM2;
end ARH_MS_NUMĂRĂTOR_8;
entity MUX2_LA_1_PE_2_BIŢI is
begin
with SEL select
Y <= A after MUX_DELAY when '0',
B after MUX_DELAY when '1',
"XX" when others;
end architecture ARH;
entity MS is
end entity MS;
architecture ARH_MS of MS is
component MUX2_LA_1_PE_2_BIŢI is
begin
STIMULI: process
begin
SEL <= 'X';
A <= "00";
B <= "11";
wait for 0 ns;
assert (Y = "XX") report "Testul a eşuat pt. SEL = X";
SEL <= '0';
wait for 40 ns;
assert (Y = "00") report "Testul a eşuat pt. SEL = 0";
A <= "01";
wait for 20 ns;
assert (Y = "01") report "Testul a eşuat pt. SEL = 0 -
Y nu s-a modificat";
SEL <= '1';
wait for 20 ns;
assert (Y = "11") report "Testul a eşuat pt. SEL = 1";
B <= "10";
wait for 20 ns;
assert (Y = "10") report "Testul a eşuat pt. SEL = 1 -
Y nu s-a modificat";
...
end process STIMULI;
3. Desfăşurarea lucrării
3.1 Se vor testa şi implementa toate exemplele de module de
simulare din lucrare.
3.2 Se vor determina stimulii de test optimi pentru exemplele din
această lucrare.
3.3 Se vor crea module de simulare, inclusiv alegerea setului adecvat
de stimuli de test, pentru exemplele din lucrările nr. 6 şi 7.
3.4 Pentru exemplul de mai jos, se va crea un modul de simulare şi
se vor alege vectorii de test cei mai adecvaţi:
200 LIMBAJUL VHDL
library IEEE;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.STD_LOGIC_1164.all;
entity COUNTER is
port( ZERO : out STD_LOGIC;
CLK, LOAD_COUNT, RESET : in STD_LOGIC;
COUNT : in STD_LOGIC_VECTOR(3 downto 0); );
end COUNTER;
begin
end COUNTER;
LUCRAREA NR. 12
PACHETE STANDARD ŞI PREDEFINITE
1. Scopul lucrării
Lucrarea prezintă rolul pachetelor predefinite şi standardizate în
cadrul proiectării sistemelor hardware în VHDL. Se studiază pachetele
STANDARD, TEXTIO şi STD_LOGIC_1164, după care sunt trecute în
revistă pachetele aritmetice şi logice ale principalelor firme producătoare de
instrumente integrate de proiectare cu VHDL.
2. Consideraţii teoretice
2.1 Generalităţi
package STANDARD is
-- Tipuri enumerate predefinite
type BOOLEAN is (FALSE, TRUE);
type BIT is (’0’, ’1’);
type CHARACTER is
(NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL,
BS, HT, LF, VT, FF, CR, SO, SI,
DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB,
CAN, EM, SUB, ESC, FSP, GSP, RSP, USP,
’’, ’!’, ’”’, ’#’, ’$’, ’%’, ’&’, ’’’,
’(’, ’)’, ’*’, ’+’, ’,’, ’-’, ’.’, ’/’,
’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’,
’8’, ’9’, ’:’, ’;’, ’<’, ’=’, ’>’, ’?’,
’@’, ’A’, ’B’, ’C’, ’D’, ’E’, ’F’, ’G’,
’H’, ’I’, ’J’, ’K’, ’L’, ’M’, ’N’, ’O’,
’P’, ’Q’, ’R’, ’S’, ’T’, ’U’, ’V’, ’W’,
’X’, ’Y’, ’Z’, ’[’, ’\’, ’]’, ’^’, ’_’,
’`’, ’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’,
’h’, ’i’, ’j’, ’k’, ’l’, ’m’, ’n’, ’o’,
’p’, ’q’, ’r’, ’s’, ’t’, ’u’, ’v’, ’w’,
’x’, ’y’, ’z’, ’{’, ’|’, ’}’, ’~’, ’DEL’);
type SEVERITY_LEVEL is (NOTE, WARNING, ERROR, FAILURE);
-- Tipuri numerice predefinite
type INTEGER is range –2_147_483_648 to –2_147_483_647;
type REAL is range –16#0.7FFFFF8#E+32 to 16#0.7FFFFF8#E+32;
-- Tipul TIME predefinit
type TIME is range –9_223_372_036_854_775_808
to 9_223_372_036_854_775_807; -- pentru implementarea
-- pe 64 de biţi
units fs; -- femtosecundă
ps = 1000 fs; -- picosecundă
ns = 1000 ps; -- nanosecundă
us = 1000 ns; -- microsecundă
ms = 1000 us; -- milisecundă
sec = 1000 ms; -- secundă
min = 60 sec; -- minut
hr = 60 min; -- oră
end units;
-- Funcţia care returnează timpul curent al simulării
function NOW return TIME;
-- Sub-tipuri numerice predefinite
subtype NATURAL is INTEGER range 0 to INTEGER’HIGH;
subtype POSITIVE is INTEGER range 1 to INTEGER’HIGH;
-- Tipuri tablou predefinite
type STRING is array (POSITIVE range <>) of CHARACTER;
type BIT_VECTOR is array (NATURAL range <>) of BIT;
end STANDARD;
204 LIMBAJUL VHDL
Observaţie
Rolul acestor constrângeri în VHDL’87 era acela de a evita
comunicaţia între procese prin intermediul fişierelor. Asemenea manipulări
ar fi generat un cod VHDL dependent de implementare, deci ne-portabil. În
VHDL’87 era imposibil să scriem într-un fişier din interiorul unui proces,
să-l închidem şi apoi să-l redeschidem din interiorul altui proces.
Începând cu apariţia VHDL’93, aceste lucruri devin posibile şi prin
urmare au fost introduse 2 noi primitive: FILE_OPEN şi FILE_CLOSE, care
sunt declarate în mod automat cu tipul TEXT. Alte îmbunătăţiri aduse de
VHDL’93 sunt: trecerea parametrilor procedurilor READLINE şi
WRITELINE în mod inout şi declararea explicită a funcţiei ENDFILE ca
funcţie impură.
procedure READ(L: inout LINE; VALUE: out BIT; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out BIT);
procedure READ(L: inout LINE; VALUE: out BIT_VECTOR; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out BIT_VECTOR);
procedure READ(L: inout LINE; VALUE: out BOOLEAN; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out BOOLEAN);
PACHETE STANDARD ŞI PREDEFINITE 207
procedure READ(L: inout LINE; VALUE: out CHARACTER; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out CHARACTER);
procedure READ(L: inout LINE; VALUE: out INTEGER; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out INTEGER);
procedure READ(L: inout LINE; VALUE: out REAL; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out REAL);
procedure READ(L: inout LINE; VALUE: out STRING; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out STRING);
procedure READ(L: inout LINE; VALUE: out TIME; GOOD: out BOOLEAN);
procedure READ(L: inout LINE; VALUE: out TIME);
package EXEMPLU is
procedure ACHIZIŢIE-TRAS(DATĂ: out TIME; VALOARE: out BIT);
end EXEMPLU;
10 ns 1
Observaţii
Două apeluri succesive ale procedurii ACHIZIŢIE_TRAS provoacă
scrierea celei de-a doua trasări în continuarea celei dintâi, în fişierul FIŞIER.
Dacă declaraţia acestui fişier s-ar fi efectuat în partea declarativă a
procedurii (şi nu, ca în exemplul de mai sus, în zona declarativă a
pachetului), atunci fişierul ar fi fost redeschis la fiecare apel şi nu s-ar fi
păstrat decât ultima trasare!
Pentru a scrie o procedură de achiziţie mai realistă, ar fi preferabil să
utilizăm procedurile READ care returnează o valoare booleană de control
(ultimul parametru). Testarea acestui parametru ar permite detectarea
erorilor (introducerea unei valori de alt tip decât cel aşteptat) şi tratarea lor
(de exemplu, prin declanşarea unei noi achiziţii).
library IEEE;
use IEEE.STD_LOGIC_1164.all;
1
Se spune despre un semnal care are o rezistenţă legată la borna de alimentare de potenţial
pozitiv. În consecinţă, în absenţa oricărei comenzi (de exemplu, în cazul unei intrări
neconectate), semnalul ia valoarea logică ’1’.
PACHETE STANDARD ŞI PREDEFINITE 211
de rezoluţie a semnalelor de acest tip STD_LOGIC, deja prezentată în cadrul
lucrării nr. 8 referitoare la domeniul concurent în VHDL).
------------------------------------------------------------
| U X 0 1 Z W L H - | |
------------------------------------------------------------
('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U'),-- | U |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'),-- | X |
('U', 'X', '0', 'X', '0', '0', '0', '0', 'X'),-- | 0 |
('U', 'X', 'X', '1', '1', '1', '1', '1', 'X'),-- | 1 |
('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', 'X'),-- | Z |
('U', 'X', '0', '1', 'W', 'W', 'W', 'W', 'X'),-- | W |
('U', 'X', '0', '1', 'L', 'W', 'L', 'W', 'X'),-- | L |
('U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X'),-- | H |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'),-- | - |
Observaţii
’X’, ’W’ şi ’U’ se numesc valori meta-logice şi natura lor este
diferită de cea a celorlalte semnale. Proiectantul trebuie să manifeste
prudenţă în cazul utilizării lor. De exemplu, rezultatul unei simple
comparaţii poate fi eronat: expresia ’U’ < ’0’ este întotdeauna adevărată
(conform semanticii de simulare), datorită definiţiei tipului enumerat, însă
această expresie nu are un sens real.
Valoarea ’-’ („fără importanţă”) nu are nici o semnificaţie pentru
simulare şi ea nu trebuie să apară niciodată în urma rezultatelor unei
simulări. Utilizarea sa este rezervată sintezei: ea le oferă instrumentelor de
sinteză posibilitatea de a codifica această valoare în ’0’ sau ’1’, în funcţie de
optimizările urmărite.
-- Tipul rezolvat STD_LOGIC este cel care apare cel mai adesea în
-- definiţiile modelelor industriale. Din raţiuni de simplitate, se
-- practică o utilizare abuzivă a tipului rezolvat chiar şi pentru
-- un semnal uni-sursă.
subtype STD_LOGIC is RESOLVED STD_ULOGIC;
--Supraîncărcarea operatorilor
function "and" (L: STD_ULOGIC; R: STD_ULOGIC) return UX01;
function "nand"(L: STD_ULOGIC; R: STD_ULOGIC) return UX01;
function "or" (L: STD_ULOGIC; R: STD_ULOGIC) return UX01;
function "nor" (L: STD_ULOGIC; R: STD_ULOGIC) return UX01;
function 'xor" (L: STD_ULOGIC; R: STD_ULOGIC) return UX01;
function 'not" (L: STD_ULOGIC) return UX01;
--Funcţii de conversie
function TO_BIT (S: STD_ULOGIC; XMAP: BIT:='0') return BIT;
function TO_BITVECTOR (S: STD_LOGIC_VECTOR; XMAP: BIT:='0') return
BIT_VECTOR;
function TO_BITVECTOR (S: STD_ULOGIC_VECTOR; XMAP: BIT:='0') return
BIT_VECTOR;
function TO_STDULOGIC (B: BIT) return STD_ULOGIC;
function TO_STDLOGICVECTOR (B: BIT_VECTOR) return STD_LOGIC_VECTOR;
function TO_STDLOGICVECTOR (S: STD_ULOGIC_VECTOR) return STD_LOGIC_VECTOR;
function TO_STDULOGICVECTOR (B: BIT_VECTOR) return STD_ULOGIC_VECTOR;
function TO_STDULOGICVECTOR (S: STD_LOGIC_VECTOR) return STD_ULOGIC_VECTOR;
--Detectarea fronturilor
function RISING_EDGE (signal S: STD_ULOGIC) return BOOLEAN;
function FALLING_EDGE (signal S: STD_ULOGIC) return BOOLEAN;
Observaţie
Luarea în considerare a valorilor implicite sau a valorilor iniţiale
constituie o problemă foarte serioasă care apare la sinteză. Unii proiectanţi
le utilizează în modelele lor ca nişte valori care apar ca urmare a unui
semnal de reset. Cu toate acestea, pentru aceste valori, nu există nici o
interpretare standard unanim recunoscută. Proiectanţii trebuie să fie
conştienţi că un model scris astfel nu este portabil de la un instrument de
sinteză la altul. Dacă funcţionalitatea modelului depinde de valorile iniţiale,
iniţializarea acestora trebuie să fie făcută în mod explicit ca urmare a
apariţiei unui eveniment.
Pentru celelalte valori ale tipului STD_ULOGIC, ‘Z’, ‘U’, ‘W’ şi ‘X’
(valoarea ‘-‘ va fi studiată separat), semnificaţiile respective depind de
utilizarea acestor valori. Se pot distinge patru cazuri:
1. Valoarea este utilizată ca valoare implicită sau ca valoare iniţială.
În acest caz nu este definită nici o semantică (a se vedea
observaţia de mai sus);
2. Valoarea este asignată unei variabile sau unui semnal. În acest
caz, valorile ‘U’, ‘W’ şi ‘X’ vor fi considerate „fără importanţă”.
Valoarea „fără importanţă” (‘-‘) poate fi înlocuită la sinteză fie
cu un ‘0’ fie cu un ‘1’. Valoarea ‘Z’ va solicita instrumentului de
sinteză generarea unui amplificator cu trei stări (tri-state). Ieşirea
acestui amplificator va constitui ţinta instrucţiunii de asignare;
3. Valoarea este utilizată într-o comparaţie implicită prin
intermediul instrucţiunii case. Instrucţiunile care apar atunci sunt
ignorate (aici se vede foarte clar diferenţa de semantică dintre
sinteză şi simulare);
4. Valoarea este utilizată de către un operator de comparare ca
expresie a unei condiţii în cadrul unei instrucţiuni if. Expresiile
A = B şi A /= B returnează FALSE, respectiv TRUE dacă unul
dintre operanzi utilizează una dintre valorile: ‘U’, ‘W’ sau ‘X’.
Comparaţiile realizate cu ajutorul operatorilor „>”, „>=”, „<”,
„<=” returnează, toate, FALSE.
PACHETE STANDARD ŞI PREDEFINITE 215
Valoarea „fără importanţă” este foarte utilă şi este foarte utilizată în
cadrul sintezei. Ea permite două funcţionalităţi:
1. Atunci când valoarea se află în membrul drept al unei
instrucţiuni de asignare, este posibilă optimizarea.
S <= ‘-‘;
V := ‘-‘;
ARRAY_S <= “----“;
Observaţii
Cele două tipuri SIGNED şi UNSIGNED sunt definite ca tipuri noi
şi NU ca sub-tipuri ale lui BIT_VECTOR sau STD_LOGIC_VECTOR.
Graţie acestei precauţii, obiectelor de tipul SIGNED sau UNSIGNED nu li
se vor putea asigna valori decât cu ajutorul procedurilor sau funcţiilor puse
special în acest scop la dispoziţia proiectanţilor. În caz contrar, ar fi fost
posibilă amestecarea obiectelor de tip SIGNED sau UNSIGNED, fără a avea
un control formal asupra lor.
Se observă, în cazul pachetului NUMERIC_STD, că a fost preferat
tipul STD_LOGIC în locul lui STD_ULOGIC, datorită faptului că primul
este mai general, fiind rezolvat, şi astfel poate fi aplicat fără constrângeri în
orice context. Ideal ar fi fost să se ofere ambele posibilităţi, dar această
abordare ar fi impus definirea de multe alte definiţii de tipuri şi de funcţii
asociate, ceea ce ar fi complicat foarte mult contextul general de lucru.