joi, 10 februarie 2011

Capitolul VII

    Trecerea la ingineria reală.

7.1    Noţiuni generale.

Până acum am învăţat cum să specificăm un sistem în Verilog, şi deci e timpul să discutăm despre sinteza lor.
Vom învăţa deci cum să specificăm un sistem ca el se poată sintetiza de instrumentele de sinteză in mod automat.
Înainte de a pleca mai departe trebuie să înţelegem subrutinele task şi function. Ele au careva asemănări şi deosebiri pe care le vom precăuta în secţiunea 2, şi vom precăuta unele predefinite dintre ele.
În secţiunea 3 vom da noţiuni despre sinteza specificărilor Verilog. Deoarece nu toate construcţiile Verilog se pot sintetiza, vom precăuta metode şi stiluri de organizare a codului pentru o implementare mai efectivă.
În secţiunea 4 vom da descriere mai amănuntă sintezei şi vom analiza sinteza automatelor finite.



7.2    Task-uri şi funcţii

7.2.1    Subrutinele Verilog
Ca şi în alte limbaje de programare în Verilog e posibilă utilizarea diferitor coduri în diferite specificaţii. Exemple tipice de reutilizare a codului pot fi specificaţii funcţionale a unor construcţii sau protocoale de interfaţă. Dacă avem nevoie să reutilizăm un bloc sau un protocol de interfaţă, fără a ieşi din specificaţie, ele trebuiesc incluse într-o subrutină. În Verilog sunt două  tipuri task şi function.
Reentrabilitatea are sens nu numai  pentru utilizarea task-urilor şi funcţiilor. Foarte des o bucată de cod care nu se utilizează undeva în altă parte, este separată într-o subrutină pentru ca codul să fie mai citeţ şi mai singur. Multe instrucţiuni şi operaţii ale microprocesorului sunt concepute în aşa mod.
Task-urile şi funcţiile se utilizează în aceleaşi scopuri (de reentrabilitate) însă ele mult diferă.

După caracter.
Ambele construcţii sunt construcţii de cod comportamentale, adică conţin numai expresii comportamentale şi se utilizează numai în blocurile comportamentale (iniţial, always). Se pot utiliza la fel şi alte subrutine, însă cu careva restricţii.
În interiorul subrutinilor se pot defini variabile locale, regiştri şi întregi, însă nu şi variabile de tip net.

 Declararea
Ambele subrutine se declară în interiorul modulului şi sunt locale pentru modulul în care sunt declarate pentru a utiliza taskurile sau funcţiile în diferite module, ele trebuiesc declarate  într-un fişier aparte care se poate include utilizând directiva compilatorului include.

Timpul de simulare
task: nu există restricţii pentru utilizarea unor evenimente sau expresii temporale în intreriorul unui task. În consecinţă, taskurile  se pot executa cu timpul specificat de proiectant.
function: Utilizarea evenimentelor sau a expresiilor temporale nu este posibilă în funcţii. Funcţiile se execută într-o unitate de timp a simulatorului.

Activarea altor subrutine.
task: Nu există vre-o limită pentru activarea altor subrutine în interiorul unui task, adică un task poate chema o altă funcţie sau task.
function: Din cauza restricţiilor în utilizarea relaţiilor temporale, o funcţie nu poate chema un task, chiar dacă taskul nu are vre-o relaţie de acest gen. Însă nu sunt restricţii la chemarea unei alte funcţii.

 Argumente
task: Numărul de argumente pentru un task este nelimitat. Un task poate avea zero sau mai multe argumente de orice tip: input, output sau inout. Pe de altă parte task-ul nu returnează vre-o valoare însă poate transmite valori prin input sau output.
function: Fiecare funcţie trebuie să aibă cel puţin un argument de intrare şi nici unul de ieşire. Rezultatul executării unei funcţii este o singură valoare, care se returnează prin numele ei.

Utilizare
task: Taskurile pot fi utilizate pentru orice cod Verilog ce conţine reţineri, evenimente sau relaţii temporale. Se pot utiliza în diferite scopuri şi poate avea mai multe valori de ieşire. Taskurile se include ca blocuri aparte.
function: Funcţiile sunt menite în special pentru a reacţiona la careva semnale de intrare (cel mai des unul) ca un singur răspuns. Din cauza limitelor în relaţiile temporale, funcţiile se referă la blocuri combinaţionale pure, de tipul conversiei şi calculelor. Funcţiile se include ca operanţi în expresii.
7.2.2    Declaraţia Task-ului.
Un task poate fi privit ca un bloc de cod ce are nume cu definire de intrări ieşiri şi bidirecţionale. Aceasta permite o privire mult mai abstractă la specificarea unui sistem şi asigură ca acelaşi bloc de cod  să poată fi reutilizat în mai multe locuri a unei descrieri.
În specificarea unui task vom trece următoarea procedură.
1.    Se specifică codul care va fi incapsulat ca un task. Dacă el reprezintă mai mult decât o expresie, se introduce într-un bloc begin-end.
2.    Se determină rolul fiecărei variabile în interiorul secţiunii: intrare, ieşire sau variabilă locală sau temporală, şi se specifică înaintea blocului dat.
3.    Se defineşte numele taskului şi se specifică după cuvântul cheie task însă înaintea blocului de cod şi declaraţii. Se adaugă cuvântul cheie endtask la sfârşitul blocului.
Task ;
        ;
        ;
endtask
ex.
task factorial;
     output [31 : 0] outfact;
     input [3 : 0] n;
      integer count;
  begin
      outfact=1;
      for (count=n; count>0; count=count-1)
                  outfact=outfact+count;
   end
endtask



6.1.1        Chemarea unui task.Un task se poate invoca (sau activa, chema) în orice bloc comportamental a unui modul unde e definit acest task. Chemarea se face printr-o expresie separată de tipul:
Taskname ();
Cheia de acces este în lista de argumente. În aşa mod, primul argument va fi acordat cu prima variabilă, de intrare sau ieşire, declarată în task. În termeni mai practici, la chemarea unui task, asocierea argumentelor cu variabilele de intrare/ieşire poate fi privită ca o substituire formală a lor cu cele reale.




7.2.4    Declaraţia de funcţie.
Diferenţa dintre taskuri şi funcţii se reflectă şi în modulul lor de definire şi chemare (chemare).
Mai întâi de toate funcţia returnează un singur rezultat care este accesibil prin chemarea de funcţie. Aceasta cere o atribuie la o variabilă locală cu acelaşi nume ca şi funcţia.
În al doilea rând, rezultatul unei funcţii predefinit este un registru de un bit. Dacă avem nevoie de un alt tip de variabilă pentru returnarea de către funcţie, acest tip se specifică în headerul funcţiei.
Al treilea. Partea declarativă poate conţine numai declaraţii de intrări şi variabile locale. Ieşiri sau bidirecţionale nu sunt admise.
Şi în sfârşit, funcţia începe cu cuvântul cheie function şi se termină cu endfunction.

function []
   ;
   [];
 begin
    ;
    ;
 end
endfunction

ex.
function [31:0] factorial;
   input [3:0] operand;
   reg   [3:0] i;
     begin
       factorial=1;
          for (i=2; i<=operand; i=i+1)
              factorial=i+factorial;
     end
endfunction 
7.2.5    Chemarea funcţiei.
Spre deosebire de taskuri care se invocă printr-o expresie separată, chemarea de funcţie este un operand. Practic asta înseamnă că funcţia se poate atribui unei variabile, poate apărea într-o expresie care e atribuită unei variabile sau chemată ca un argument al altei funcţii.
Rezultatul funcţiei se returnează prin numele de funcţie. Intern ea e realizată ca o declraţie implicită a unei variabile cu acelaşi nume şi tip ca şi funcţia.
Ex. function PartyByOdd;
        input [15:0] DataVectorlong;
        begin
           PartyByOdd=^DataVectrolong;
       end
     endfunction   
………………………
Flags[3] =PartylyOdd(RegAX)
………………………
Select=PartyLyOdd(RegAX)&RegAX[0];
………………………
If (PartyLyOdd(AddressBuss))
…………………………