CID Aplicatii 3

De la WikiLabs
Jump to navigationJump to search

Programarea unui FPGA – Introducere

FPGA-ul (Field-programmable gate array) este un circuit programabil, capabil sa implementeze un anumit circuit definit de utilizator si este format dintr-o matrice de blocuri programabile, interconectate intre ele printr-o serie de conexiuni programabile. Aceste blocuri pot implementa atat functii logice, cat si memorii.

Cand se doreste implementarea unui circuit pe FPGA, acesta urmeaza mai multe etape: sinteza, implementarea, generarea fisierului de implementare si programarea.

Sinteza este procesul prin care codul Verilog este transformat intr-un circuit la nivel de porti si registre si este independent de modelul de FPGA folosit.

Implementarea este procesul prin care circuitul obtinut la pasul anterior este transformat in circuit la nivel de blocuri disponibile pe FPGA. Acest pas este dependent de FPGA-ul folosit.

Registrul de Tip D sau bistabilul, este un circuit de memorie ce poate memora date la momentul aparitiei unui eveniment front crescator de ceas (vom discuta despre acesta in detaliu mai tarziu). MUX este un multiplexor si este capabil sa selecteze pentru iesire datele de la bistabil, sau datele de la LUT (Look-Up Table). Acest LUT este o memorie ROM capabila sa stocheze date ce vor fi accesate cu ajutorul intrarilor (intrarile au rol de adresa). LUT-ul este secretul din spatele implementarii functiilor logice. Circuitele implementate pe FPGA nu sunt efectiv porti interconectate intre ele, ci memorii ROM (LUT) care stiu sa memoreze iesirile asociate unor combinatii de intrare.

Asadar, in timpul implementarii, functiile logice sunt transformate in tabele de adevar (pentru fiecare combinatie de intrare se calculeaza iesirea iesirea), care sunt implementate prin LUT-uri.

Circuitul dezvoltat de utilizator trebuie legat apoi la pini fizici ai FPGA-ului, pentru a putea stimula intrarile si a observa starile iesirilor. Aceasta legare la pinii fizici este posibila, deoarece, asa cum am mentionat si mai sus, conexiunile in interiorul FPGA-ului sunt programabile. Pe placa, avem comutatoare si butoane pentru a controla starea intrarilor si LED-uri si afisaje pentru a observa starea iesirilor.

In figura de mai jos este prezentata o schema simplificata a conectarii modulului implementat pe FPGA la pinii fizici. Fiecare pin fizic este codat in tool-ul de sinteza cu un anumit cod. Mentionand in fisierul de constrangeri in dreptul fiecarui bit al fiecarei intrari si iesiri codul aferent pinului fizic, tool-ul va programa conexiunile programabile astfel incat portul modulului sa fie conectat la pinul fizic ales. Mai departe, pe placa de dezvoltare ce contine si FPGA-ul, pinii fizici sunt conectati prin trasee metalice la dispozitivele de control si observatie.

Folosind toate aceste informatii (implementarea circuitului si modul de conectare la porturile fizice ale FPGA-ului) se va genera fisierul de implementare, ce va fi apoi descarcat in memoria SRAM a FPGA-ului, configurand astfel dispozitivul.

Exemplul 1

In exemplul de mai jos, vom descrie comportamental un comparator si il vom testa prin simulare. Comparatorul pe care il vom descrie este un circuit cu 2 intrari pe 4 biti si 3 iesiri pe un bit.


Implementarea in Verilog a circuitului

module Comparator(
    output reg equal,
    output reg lower,
    output reg greater,
    input [3:0] in0,
    input [3:0] in1
);
always@(in0 or in1) begin
if(in1 > in0) begin
    equal = 0;
    lower = 0;
    greater = 1;
end else if(in1 == in0) begin
    equal = 1;
    lower = 0;
    greater = 0; 
end else begin
    equal = 0;
    lower = 1;
    greater = 0; 
 end
end
endmodule


Implementarea in Verilog a modulului de test

`timescale 1ns/1ps
module Comparator_TB();
 
 wire equal_t;
 wire lower_t;
 wire greater_t;
 reg [3:0] in0_t;
 reg [3:0] in1_t;
 
 initial begin
       in0_t = 0;
       in1_t = 0;
   #1  in0_t = 1;
   #1  in1_t = 2;
   #1  $stop(); 
 end
 
 Comparator DUT(
    .equal(equal_t),
    .lower(lower_t),
    .greater(greater_t),
    .in0(in0_t),
    .in1(in1_t)
 );
endmodule

Observatii:

  • Cele 3 iesiri ale modulului Comparator sunt de tip reg deoarece isi modifica valoarea intr-un bloc de tip always.
  • Fiind vorba de un circuit combinational, blocul de tip always este sensibil la orice modificare a oricarui semnal de intrare. De aceea, punem in lista de sensitivitati ambele semnale de intrare. Mai simplu, pentru a fi siguri ca nu uitam niciun semnal pentru blocurile always mai complexe, putem pune * in lista de sensitivitati (always@(*) begin).
  • Pentru modulul de test (Comparator_TB), observam ca interfata acestuia este goala (nu exista intrari sau iesiri).
  • Pentru fiecare intrare a modulului testat se defineste un semnal de tip reg, iar pentru fiecare iesire se defineste un semnal de tip wire. Atentie! Dimensiunea acestor semnale trebuie sa corespunda cu dimensiunea semnalelor din interfata modului la care vor fi legate.
  • Aici s-a optat pentru un test simplu, generand cate o combinatie pentru fiecare caz (egalitate, mai mic, mai mare), obsevatia facandu-se direct pe forma de unda (fara evaluare automata).


Exemplul 2

In exemplul de mai jos, vom implementa un circuit de adunare pe 4 biti, folosind sumatoare pe 1 bit.