Hardware reconfigurabil: o nouă paradigmă arhitecturală

Mihai Budiu -- mihaib+@cs.cmu.edu
http://www.cs.cmu.edu/~mihaib/

7 iunie 1998

Subiect:
hardware reconfigurabil prin software
Cunoștințe necesare:
cunoștințe elementare despre arhitectura calculatoarelor
Cuvinte cheie:
poartă, memorie, procesor, FPGA, ASIC


Contents




Despre hardware reconfigurabil am auzit cu puțina vreme în urmă; atracția a fost însă imediată. Acest articol va încerca să vă transmită o parte din motivele pentru care domeniul mi se pare demn de atenție. Unul dintre ele este faptul că relativ puțină cercetare sistematică s-a făcut în domeniul circuitelor reconfigurabile. Noțiunea în sine este destul de veche: primul prototip a fost introdus de firma Xilinx în 1986, deci cu 12 ani în urmă. O serie de conjuncturi au ținut însă zona în umbră față de atenția marilor companii și a cercetătorilor. Brusc însă, în urmă cu cîțiva ani, o creștere a activității orientate spre acest subiect a putut fi observată. Principalul motiv este tehnologia.

Tehnologia

În anii '60 Gordon Moore a observat o interesantă lege de evoluție a densității și performanței circuitelor integrate (cele două sunt strîns legate: cu cît un circuit este mai mic cu atît poate fi făcut să funcționeze mai repede, pentru că semnalele electrice trebuie să circule pe distanțe mai scurte). Moore a pronosticat că densitatea circuitelor se dublează la fiecare 18 luni. Evident, această evoluție nu poate ține la infinit, pentru că după o vreme dimensiunile componentelor ar deveni sub-atomice. Dar cît de mult se poate merge cu această rată de îmbunătățire a tehnologiei? Ei bine, experții s-au înșelat în numeroase rînduri prezicînd încetinirea evoluției: și la ora actuală legea este valabilă. Se estimează că în următorii cinci-zece ani rata de evoluție va putea fi menținută.

Evoluția tehnologiilor semiconductoarelor însă dă naștere la o creștere în salturi a celorlalte tehnologii. De exemplu, pentru că cipurile de memorii RAM sunt pătrate1, capacitatea lor în general crește în multipli de 4 (se dublează lățimea și lungimea). Deci în loc să se dubleze la fiecare 18 luni, RAM-urile se cvadruplează în capacitate la fiecare 3 ani.

Un salt mai spectaculos este evident în următorul exemplu: la începutul anilor '70 densitatea a devenit suficient de mare pentru a permite plasarea tuturor componentelor unei unități centrale pe un singur integrat. Așa a apărut microprocesorul (primul microprocesor, 4004, a fost creat de firma Intel). La începutul anilor '80 aceeași creștere a permis înghesuirea pe o singură pilulă de siliciu a tuturor tranzistorilor (între 25.000 și 50.000) pentru un microprocesor complex pe 32 de biți. Atunci cînd poți pune toate părțile la un loc de fapt saltul calitativ este mult mai mare, pentru că legăturile dintre circuite se reduc substanțial, și performanța crește brusc.

La ora actuală cele mai complexe microprocesoare (Pentium II de pildă) au peste 15,000,000 de tranzistori! Cu aceeași rată de evoluție, în același spațiu în 2005 vor încăpea peste 1 miliard de tranzistori.

Tot evoluția tehnologică a scos și circuitele reconfigurabile, despre care vorbeam mai sus, din anonimat. Subit ele au devenit suficient de mari și de complicate pentru a putea implementa în mod eficient aplicații interesante.

Două motive fac deci interesant studiul circuitelor reconfigurabile:

Ce este deci hardware-ul reconfigurabil? Înainte de a răspunde la această întrebare voi face o scurtă și incompletă trecere în revistă a celorlalte paradigme hardware folosite. Prin contrast vom înțelege mai bine care sunt calitățile și lipsurile noii generații de circuite.

Hardware-ul tradițional

Putem distinge două feluri de circuite: care pot fi programate și care nu. Din prima categorie fac parte microprocesoarele, din a doua circuitele integrate specifice unei aplicații (ASIC: Application Specific Integrated Circuits). Vom vedea și niște categorii intermediare.

Microprocesoare

Un microprocesor este practic o colecție de unități funcționale plasate pe ceea ce se numește ``data-path'' (cărare a datelor?). Simplificată la maximum, funcționarea unui procesor poate fi descrisă în următorii termeni:

  1. Procesorul citește din memorie următoarea instrucțiune de executat;

  2. Procesorul decodifică instrucțiunea: sunt trimise semnale de comandă spre feluritele unități funcționale. Datele de prelucrat sunt extrase de unde se află (probabil din regiștrii) și trimise spre una dintre unitățile funcționale (de exemplu, dacă trebuie executată o instrucțiune de adunare, datele sunt trimise la unitatea care face adunări);

  3. Unitatea funcțională activă prelucrează datele și generează rezultatul;

  4. Rezultatul este trimis la destinația sa (posibil un registru);

  5. Ciclul se reia de la pasul 1.

Să observăm următoarele caracteristici ale unui microprocesor, pe care le vom contrasta apoi cu cele ale hardware-ului reconfigurabil:

Un microprocesor trebuie să fie ``bun la toate'' și nu este excelent pentru nimic. Anumite tipuri de calcule nu pot fi făcute cu procesoare din această cauză; este nevoie de ASIC-uri.

ASIC-uri

Atunci cînd știi exact ce ai de calculat și timpul disponibil este foarte puțin, nu ai de ales altceva decît să proiectezi un circuit care face numai acel lucru. Un astfel de integrat, construit să rezolve o singură problemă, se numește ASIC.

Un exemplu tipic de ASIC este cipul DES care criptează cu algoritmul de criptografie cu cheie privată Data Encryption Standard. Într-un PC se găsesc o grămadă de ASIC-uri, de la controlerele de magistrală la controlerele perifericelor. (Într-un PC se pot găsi și mai multe procesoare; unele periferice sunt controlate de procesoare al căror program este fixat odată pentru totdeauna.)

Un ASIC este mult mai simplu, mai ieftin și mai rapid decît un microprocesor. Dar nu este deloc flexibil: nu poate rezolva decît o singură problemă.

Microcod; circuite configurabile

Atît microprocesoarele2 cît și ASIC-urile sunt construite din fabrică și așa rămîn pînă la moarte. Există însă niște clase de circuite care pot fi modificate de către utilizator, la o scară redusă.

Procesoarele cu set de instrucțiuni complex (CISC: Complex Instruction Set Computer) sunt adesea implementate folosind în interior microcod. Practic acțiunile indicate mai sus: decodificarea instrucțiunii, execuția, scrierea rezultatului, etc., sunt mult mai complexe pentru un CISC, și sunt fiecare descompuse la rîndul lor în instrucțiuni mai simple. Pentru fiecare pas se execută deci un progrămel, numit microprogram, care indică fiecărei unități funcționale ce să facă. Microprogramul este de obicei înscris într-o memorie ROM din interiorul procesorului. 'Procesoarele CISC mai vechi uneori permiteau utilizatorilor să schimbe microcodul în timpul funcționării, permițînd sinteza de noi instrucțiuni, care nu existau la fabricarea procesorului. Libertatea era însă relativ limitată. (Microprocesorul Pentium Pro permite ``microcode patching'': peticirea microcodului. Aceasta este o tehnologie introdusă de Intel după apariția celebrului bug din Pentium, care efectua greșit împărțirea. Algoritmul de împărțire era scris în microcod și avea un bug. Acum Intel poate corecta astfel de erori chiar după ce procesorul a fost livrat utilizatorilor, prin software. Acest subiect însă depășește cadrul acestui articol.)

O altă varietate de circuite configurabile conține, printre altele, clasa numită PLA: Programmable Logic Array. Acest tip de circuite poate fi modificat ``off-line'' (adică nu în timp ce funcționează). Un PLA tipic conține un rînd de porți SAU și un rînd de porți ȘI. Fiecare ieșire de la o poartă SAU este conectată la fiecare intrare la o poartă ȘI, avînd astfel o matrice de conexiuni. Cel care folosește circuitul poate suda sau desface unele dintre conexiuni, obținînd felurite funcționalități. Pentru că orice funcție logică se poate exprima folosind o conjuncție de disjuncții, astfel se poate (teoretic) sintetiza orice circuit. Desigur că metoda nu este practică pentru circuite complicate, dar este folosită cîteodată pentru a sintetiza ``glue logic'': circuite care fac legătura între alte circuite.

Motivul pentru care PLA-urile sunt importante este unul economic: desigur că am putea fabrica un ASIC pentru fiecare funcționalitate a unui PLA, dar atunci ar costa mult mai mult. Toate PLA-urile sunt de fapt la fel, deci sunt fabricate de o singură linie tehnologică, pe cînd fiecare ASIC care calculează o altă funcție este diferit, deci are nevoie de propria lui linie de fabricație.

Hardware reconfigurabil

Am văzut deci că hardware-ul tradițional are în general o funcționalitate fixată de la bun început de către fabricant; această funcționalitate poate fi controlată și multiplexată în timp, ca la microprocesoare, pentru a sintetiza funcții noi, sau poate fi fixată odată pentru totdeauna, ca la ASIC-uri. Anumite genuri de circuite pot fi făcute să facă lucruri pentru care nu au fost proiectate (ca procesoarele cu microcod), sau pot fi schimbate cu un efort considerabil (ca PLA-urile).

Ce-ar fi însă dacă am avea un circuit a cărui funcționalitate să poată fi schimbată la fel de repede pe cît funcționează (spre deosebire de PLA, la care treaba asta durează minute sau ore), și care să permită o flexibilitate totală (spre deosebire de microcod, care poate doar controla unitățile funcționale existente)? Ce-ar fi dacă circuitele astea s-ar putea configura prin aceleași mecanisme folosite pentru a le folosi (spre deosebire de anumite memorii EEPROM care sunt șterse prin expunere la ultraviolete)? Ce-ar fi dacă am avea un circuit care ar putea să-și schimbe funcționalitatea în timp ce lucrează?

Există așa ceva? Da; se numește hardware reconfigurabil.

Caracteristici fizice

Un circuit hardware reconfigurabil constă din două entități distincte: porți logice și sîrme care leagă porțile. Spre deosebire de circuitele VLSI obișnuite, funcționalitatea unei porți nu este fixată, ci poate fi schimbată dinamic. De asemenea, sîrmele se întind de-a lungul circuitului, iar la fiecare intersecție se află un mic comutator. Fiecare comutator poate fi închis sau deschis prin software. Un circuit reconfigurabil generic arată cam ca în figura 1.

Figure 1: Circuit reconfigurabil.
\begin{figure}\centerline{\epsfxsize=8cm\epsffile{reconfigurabil.eps}}\end{figure}

Tehnologic problema este foarte simplă; ambele dispozitive se pot face reconfigurabile folosind mici celule de memorie.

Poarta universală

O poartă logică ``universală'' cu două intrări de 1 bit și o ieșire de 1 bit se poate sintetiza folosind o memorie cu capacitatea de 4 cuvinte de 1 bit. Cele două intrări sunt adresa cu care se indexează în memorie, iar conținutul memoriei este ieșirea. Iată de exemplu care cum se pot sintetiza felurite porți în acest fel:

  Conținutul memoriei
adresa $A \lor B$ $A \land B$ $\lnot A$
0 0 0 1
1 1 0 0
2 1 0 1
3 1 1 0

E clar cum lucrează? De pildă, dacă vrem să folosim memoria ca o poartă SAU ($\lor$) o să încărcăm în cei 4 biți valorile 0, 1, 1, respectiv 1. Atunci cînd vrem să calculăm ``$1 \lor 0$'', primul bit la intrare va fi 1, iar al doilea 0. Asta formează la un loc adresa 10 (2 în baza 2); cuvîntul de memorie de la adresa 2 este 1, deci $1 \lor 0 = 1$. Corect.

În terminologia hardware-ului reconfigurabil, o astfel de memorie folosită pentru a calcula valoarea unei funcții booleene se numește, din motive evidente, ``tabelă de căutare'', Look-Up Table, LUT. Blocurile logice folosite în circuitele comerciale conțin mai multe astfel de ``porți''.

Switch-ul

Cu ajutorul LUT-urilor putem schimba funcționalitatea unei porți logice. Cu ajutorul comutatoarelor (switch) putem schimba interconexiunile. Imaginați-va o grilă formată din ``sîrme'', iar la fiecare intersecție de sîrme un tranzistor, cu emitorul pe o sîrmă și cu colectorul pe cealaltă. Baza tranzistorului este cuplată la o memorie care conține un singur bit. Dacă în memorie punem un ``1'', atunci tranzistorul va conduce electric între emitor și colector, realizînd o conexiune între cele două sîrme. Dacă baza este la ``0'', atunci sîrmele sunt izolate electric una de cealaltă. Figura 2 ilustrează cum se poate conecta ieșirea unei porți la intrarea alteia.

Figure 2: Conexiunile între sîrme pot fi făcute și desfăcute cu ajutorul unui tranzistor controlat de o memorie de un bit.
\begin{figure}\centerline{\epsfxsize=6cm\epsffile{comutatoare.eps}}\end{figure}

Putem deci configura foarte simplu legăturile dintre elementele de procesare, folosind un bit pentru fiecare intersecție.



Aceste două elemente reconfigurabile, ``porțile'' și comutatoarele, fac întregul circuit extrem de flexibil. Prin simpla operațiune de scriere într-o memorie putem schimba dinamic funcționalitatea circuitului! Din această cauză voi numi astfel de circuite reconfigurabile, prin contrast cu circuitele configurabile: putem oricînd să le schimbăm cu ușurință configurația, într-un timp relativ scurt.

La ora actuală există mai multe firme care produc circuite integrate reconfigurabile comerciale. Cele mai importante sunt, în ordinea volumului de circuite de acest gen: Xilinx, Altera, AT&T, Actel, Quicklogic. Fiecare din aceste firme produce mai multe tipuri de circuite, folosind tehnologii diferite, cu diferite complexități ale tabelelor, cu mici bucățele de hardware specializat vîrîte printre porțile generice, etc. Ideea de bază însă este cea descrisă mai sus.

Denumirea acestui gen de circuite nu este încă bine împămîntenită; termenul care capătă însă cea mai mare acceptare este cel de ``matrici de porți logice programabile cu ajutorul cîmpului [electromagnetic]'': Field Programmable Gate Arrays, FPGA.

Înainte de a vedea care sunt deficiențele circuitelor reconfigurabile și problemele care sunt de rezolvat de către cercetare în ceea ce le privește, să aruncăm o privire la domeniile în care aceste circuite sunt foarte necesare.

Sisteme cu hardware reconfigurabil

Trebuie de la bun început înțeles că hardware-ul reconfigurabil nu își propune să înlocuiască celelalte paradigme de calcul, ci să le suplimenteze. Locul unităților reconfigurabile este alături de cele clasice (procesoare, ASIC-uri), pentru a executa acea parte din treabă care li se potrivește cel mai bine. Există mai multe propuneri de utilizare a acestui tip de hardware, care diferă prin gradul de integrare cu sistemul. Iată unele dintre posibilități enumerate în ordine descrescătoare a integrării:

Unitate funcțională:
fiecare microprocesor ar putea avea, pe lîngă unitatea aritmetică și logică, o unitate a cărei funcțiune este dinamic configurabilă. Instrucțiuni speciale ar configura unitatea și alte instrucțiuni ar folosi-o.

Coprocesor:
așa cum înainte de 80486 Intel avea un procesor principal și un coprocesor, putem să ne imaginăm o unitate reconfigurabilă plasată pe aceeași magistrală și comandată de procesorul principal. Modul de folosire este asemănător cu cel precedent, dar timpii de comunicare între module sunt mai mari.

Procesor independent:
putem să ne imaginăm unitatea reconfigurabilă ca fiind un master de magistrală autonom pe lîngă microprocesor, capabil să acceseze memoria, să preia date și să le prelucreze. Microprocesorul central ar iniția doar acțiunile sale, indicînd de exemplu unde în memorie se află configurația. Unitatea reconfigurabilă ar citi configurația, s-ar configura singură și apoi ar începe să execute aplicînd operații asupra unor date a căror adresă a fost indicată tot de procesorul central.

Sistem complet de calcul autonom:
pentru unele aplicații (destul de puține) se pot construi sisteme complete de calcul bazate pe circuite reconfigurabile; unele exemple apar mai jos.

Aplicații

Putem distinge două clase de aplicații: unele care în mod tradițional sunt rezolvate folosind ASIC-uri, și altele care necesită procesoare. Iată ce poate ``fura'' de la fiecare din ele noua tehnologie:

FPGA versus ASIC

Trebuie dinainte spus că dacă putem implementa aceeași soluție pe un ASIC și pe un circuit reconfigurabil, soluția cu ASIC-ul va fi mai rapidă în execuție. Motivele sunt multiple, și le vom explora în secțiunea consacrată deficiențelor. Cu toate acestea circuitele reconfigurabile nu sunt deloc inutile! Marile lor avantaje față de ASIC-uri sunt prețul scăzut și reconfigurabilitatea.

Iată deci genurile de aplicații la care se pretează excelent hardware-ul reconfigurabil:

Produse de serie mică.
Costul construirii unei linii de fabricație pentru ASIC-uri este foarte mare, pentru că fiecare ASIC cere o serie de dispozitive unice. În schimb toate FPGA-urile sunt la fel; funcționalitatea uneia este programată ulterior, prin software.

Dezvoltare de ASIC-uri.
Proiectarea și depanarea unui ASIC este o treabă deosebit de complicată3. Testarea mai ales este dificil de făcut. Desigur, nimeni nu-și permite să fabrice un ASIC numai ca să găsească un bug și să schimbe apoi întreaga linie de fabricație. Metoda uzual folosită este simularea în software, dar aceasta este extrem de lentă (de mii de ori mai lentă decît viteza de funcționare a circuitului real). O soluție foarte eficientă este de a implementa schema ASIC-ului pe un FPGA și de a-l rula astfel. Raportul de viteză este cam de genul 1/2. În plus, orice bug se poate foarte ușor corecta schimbînd configurația. Există o firmă, Quickturn, care cu asta se ocupă: îți vinde plăci mari cu sute de FPGA-uri și software care ia descrierea unui circuit într-un limbaj de descriere hardware (HDL) și construiește automat o versiune a circuitului folosind FPGA-uri. Rezultatul apoi poate fi ``înfipt'' în locul unde ar trebui să fie circuitul real și poate fi folosită pentru simulare.

``Rapid prototyping''.
Construirea unei linii de fabricație de ASIC-uri durează cîteva săptămîni în cel mai bun caz; un FPGA poate fi reconfigurat în milisecunde. Atunci cînd nu-ți poți permite să aștepți, hardware-ul reconfigurabil poate fi singura soluție fezabilă.

Toleranță la defecte.
Dacă o parte din circuitul reconfigurabil se defectează, putem reconfigura o altă parte pentru a-i prelua funcționalitatea: orice LUT poate calcula orice funcție. Există clase de circuite reconfigurabile care se auto-verifică și se auto-reconfigurează în cazul unei malfuncții, ocolind partea cu defecte, pe care pur și simplu nu o folosesc! Acest gen de aplicații abia emerge, dar este foarte promițător. NASA se interesează cu precădere de astfel de aplicații; este destul de greu să faci service pe un satelit...

Aplicații care se schimbă.
Cum spuneam, un ASIC rezolvă întotdeauna o singură problemă. Dacă anticipăm că problema se va schimba în timp (gîndiți-vă de pildă la ``upgrades'' pentru modemuri, telefoane celulare, etc.) trebuie să folosim o soluție flexibilă. Dacă problema nu este prea complicată, atunci este sinucidere financiară să folosim un microprocesor pentru a o rezolva; un circuit reconfigurabil va fi aproape întotdeauna mai ieftin. Și vom vedea mai jos că un circuit reconfigurabil are potențialul de a avea o performanță net superioară microprocesorului, pentru că microprocesorul este extrem de general, însă hardware-ul poate fi special reconfigurat pentru problema pe care vrem să o rezolvăm.

Algoritmi sistolici.
Hardware-ul reconfigurabil pare a fi ținta ideală pentru a implementa anumite clase de algoritmi masivi paraleli. De exemplu, algoritmii sistolici (în care o mulțime de elemente de procesare funcționează sincron și pasează date pentru prelucrat de la unul la altul) sau automatele celulare (în care o mulțime de procesoare foarte simple operează independent și comunică cu vecinii în mod asincron) par a fi făcute pentru acest mediu. Simetria circuitelor reconfigurabile ne permite să împărțim circuitul în bucățele care implementează astfel de automate simple.

FPGA versus procesoare

Hardware-ul reconfigurabil are șansa să bată microprocesoarele în performanță pentru anumite genuri de aplicații. Care sunt acestea? Pentru a răspunde trebuie să înțelegem de fapt unde-și petrece timpul un program.

Un procesor care rulează la 300Mhz și lansează în medie 2 instrucțiuni pe ciclu (tipic pentru un Pentium II modern) va executa 600 de milioane de instrucțiuni pe secundă. Mai mult decît numărul total de instrucțiuni din cel mai mare program scris vreodată. Este clar, timpul este petrecut re-executînd o serie de instrucțiuni de multe ori. De fapt orice program are undeva o buclă în care-și petrece majoritatea timpului. O regulă empirică spune că 90% din timp se execut'a 10% din cod; de fapt numerele sunt mai aproape de 98%/2%.

Asta înseamnă că dacă reușim să optimizăm acele 2% din program pentru a mearge de 2 ori mai rapid, întreaga durată a programului se reduce aproape la jumătate! Orice cîștig de performanță în ``cea mai interioară buclă'' (innermost loop) este foarte important.

Dacă vă uitați la caracteristicile procesoarelor enumerate mai sus, vedeți care sunt exact caracteristicile care pot fi exploatate de un circuit reconfigurabil:

Dimensiuni neobișnuite ale datelor.
Un procesor RISC o să facă adunări pe 32 de biți chiar dacă trebuie să adune numere pe 3 biți. Folosind hardware reconfigurabil putem însă genera sumatoare de orice dimensiune, adaptate pentru problema pe care vrem să o rezolvăm. Un sumator foarte mic este mult mai rapid; de aici creștere de viteză și de eficiență în ocuparea spațiului.

Instrucțiuni greu sintetizabile
de către un microprocesor. Considerați o subrutină care trebuie să inverseze biții dintr-un număr de 32 de biți: primul să devină ultimul, ș.a.m.d. Cu un procesor obișnuit aceasta se face folosind o buclă și o serie complicată de instrucțiuni care extrage biți și îi ``vîră'' în cealaltă parte; rezultatul este un program care durează sute de cicli de ceas. În hardware reconfigurabil un astfel de program nu are nevoie de nici un fel de calcule: pur și simplu tragi niște sîrme care se încrucișează: prima merge la ultima poziție, etc. Timp de execuție: aproape 0!

De fiecare dată cînd un program are nevoie de astfel de operații care se sintetizează greu din instrucțiuni primitive ale unui procesor este un candidat bun la implementarea pe un circuit reconfigurabil.

Programe care beneficiază de paralelism masiv.
Am văzut mai sus că paralelismul oferit de un procesor este relativ limitat. Uneori însă avem de-a face cu aplicații care pot prelucra cantități extrem de mari de date într-un mod uniform. Prelucrarea digitală de semnal (sunet, imagine, etc.) este un exemplu. Un FPGA poate cîștiga creînd atîtea unități funcționale cîte încap în hardware, poate zeci!

Programe care pot fi executate în regim ``pipeline''.
Anumite genuri de programe (aplicațiile vectoriale) aplică o serie lungă de operații fiecărei date dintr-un set mare. Putem sintetiza toate operațiile în hardware și putem aplica simultan operații diferite unor date diferite.

Sinteza unor circuite specifice unei instanțe (generare dinamică de cod).
Această metodă de creștere a eficienței este disponibilă parțial și procesoarelor obișnuite. Să ne gîndim la un program de criptare. Criptarea se face în funcție de o cheie, pe care utilizatorul o introduce. După ce utilizatorul introduce cheia, aceasta va rămîne constantă pentru toată durata criptării. Algoritmul poate beneficia de forma cheii pentru a deveni mai eficient. De exemplu dacă ultima cifră din cheie este 0, toate înmulțirile cu acea valoare pot fi sărite.

Această tehnologie este un subiect foarte fierbinte în teoria compilatoarelor, și se numește dynamic code generation: generezi cod abia atunci cînd știi maximum de informație. Compilatoarele de tip JIT (Just In Time), sau Hot-Spot de la Sun de pildă, folosesc chiar această tehnică.

Metoda este cu atît mai eficientă în cazul circuitelor reconfigurabile, pentru că libertatea este mult mai mare decît în cazul unui procesor în ceea ce privește ``cărămizile'' de bază.

La ora actuală cele mai rapide cipuri de criptare sunt construite folosind hardware reconfigurabil, tocmai pentru că folosesc toate tehnicile de mai sus: după ce cheia este cunoscută se generează un circuit special care criptează cu o singură cheie, și care este extrem de eficient.

Alt exemplu interesant: să considerăm setul de instrucțiuni MMX introdus de Intel pentru procesoarele sale. MMX un set de instrucțiuni foarte specializat, destinat procesării de semnale pentru aplicații multimedia. Problema principală a lui Intel este de compatibilitate: lumea se ferește să scrie programe folosind instrucțiuni MMX pentru că acestea nu se pot executa pe procesoare care nu au această extensie (sau se pot executa numai foarte lent, folosind emulare software). MMX sunt exact instrucțiuni care se pot implementa foarte simplu și eficient în hardware reconfigurabil: se aplică la date de dimensiuni bizare (de obicei pe cîte 8 biți), sunt destinate unor procesări vectoriale, care poate fi de obicei eficient tradusă în regim de pipe-line. Dacă Intel ar fi avut niște hardware reconfigurabil în Pentium, nu ar mai fi avut grija compatibilității și eficienței instrucțiunilor MMX: oricine le putea sintetiza automat la momentul execuției, și eventual, dacă se dovedea că unele dintre instrucțiuni nu erau prea folosite, puteau fi scoase din configurație, fără a schimba nimic în linia de fabricație a chipului! (Motorola a introdus de curînd o serie de procesoare care conține astfel de hardware.)

Ineficiențe; subiecte de cercetare

Să nu credeți că FPGA-urile sunt un panaceu; există o grămadă de probleme caracteristice numai lor; unele pot fi rezolvate, altele sunt probabil intrinseci:

Viteza de propagare
a semnalului este cea mai neplăcută problemă. O sîrmă într-un ASIC este un obiect aproape demn de ignorat; timpul de propagare printr-un switch de la o încrucișare într-un FPGA este însă semnificativ. Propagarea dă măsura tactului de ceas care poate fi folosit. Dacă întîmplător un semnal trebuie să traverseze mai multe încrucișări, am zbîrcit-o. Viteza unui program este deci dependentă de plasamentul fizic, care este greu de controlat de către programator.

Sîrmele:
din cauză că nu se știe dinainte ce cu ce este legat, un FPGA trebuie să conțină o mare cantitate de sîrme, pentru a permite tot felul de combinații posibile. Peste 90% din suprafața unui FPGA este ocupată de sîrme, dintre care multe rămîn nefolosite. Asta înseamnă eficiență scăzută și densitate efectivă mică de porți. Cel mai mare FPGA are de ordinul a sute de mii de porți, la aceeași suprafață cu un procesor. De aici o serie întreagă de constrîngeri pentru proiectanții de aplicații.

Compilatoarele ineficiente
sunt probabil cel mai dificil obstacol de trecut pentru acceptarea pe scară largă a fenomenului. La ora actuală lumea proiectează programe pentru circuite reconfigurabile așa cum proiectează hardware: folosind limbaje HDL și scule CAD (Computer Aided Design) pentru aranjare pe circuit. Acest procedeu este mult mai dificil decît proiectarea în limbaje de nivel înalt, și în general compilatoarele sunt mult mai lente (pentru a sintetiza progrămele de mii de linii durata poate fi de ordinul orelor!).

O altă dificultate majoră este proiectarea de programe care folosesc simultan microprocesorul și o unitate reconfigurabilă auxiliară. Cu tehnologia curentă, programatorul trebuie atunci nu numai să scrie programele pentru ambele procesoare, ci și să aibă grijă de comunicația dintre programul de pe procesor și cel de pe circuitul auxiliar. Programatorii nu sunt obișnuiți să gîndească în astfel de termeni.

În al treilea rînd avem o problemă de inadecvare a limbajelor. Un limbaj de nivel înalt, ca C-ul, exprimă uneori concepte care nu sunt ușor sau eficient de modelat pe un circuit reconfigurabil. Luînd exemplul de mai sus, cu inversarea biților, un programator nici nu poate scrie așa ceva în C decît folosind o buclă. Cum ar putea atunci un compilator pentru FPGA să observe că utilizatorul vrea de fapt doar să miște niște sîrme? Nu e un lucru evident nici pentru un om. Încă nu este clar ce fel de limbaje ar trebui folosite în domeniu.

Mărime limitată:
pentru calculatoarele obișnuite, mecanisme ca memoria virtuală și RAM mare au făcut o non-problemă mărimea unui program. Resursele unui circuit reconfigurabil sunt însă încă foarte limitate și foarte vizibile pentru utilizator. Compilarea unui program pentru un FPGA poate eșua de pildă dacă nu sunt destule sîrme într-o anumită zonă pentru a conecta două porți, chiar dacă circuitul sintetizat este relativ mic față de cantitatea totală de resurse disponibile.

Prototipul CMU

Voi încheia acest text cu descrierea sumară a cercetării care se desfășoară la Universitatea Carnegie Mellon. Proiectul are o pagină de web, dar deocamdată acp;p se află destul de puțină informație pentru că încă nu avem rezultate substanțiale4. Puteți ajunge acolo folosind o legătură din pagina mea personală de web.

Carnegie Mellon are două grupuri care lucrează la un prototip special de circuit reconfigurabil numit PipeRench. Asta vine de la ``pipe'': țeavă (subliniind natura ``pipelined'' a circuitului) și ``wrench'': cheie franceză. Circuitul acesta se vrea o unealtă generală pentru a scrie aplicații ``pipelined''. Unul dintre grupuri lucrează la proiectarea, depanarea și construirea unui circuit prototip și a interfeței sale cu un sistem de calcul (bazat pe o magistrală PCI), iar celălalt la un compilator care să genereze cod pentru PipeRench. Între cele două grupuri există o oarecare independență, în sensul că, deși pentru moment compilatorul dezvoltat are ca singură țintă prototipul PipeRench, în mod ideal ar trebui să fie ușor portat și pentru alte feluri de circuite reconfigurabile, cum ar fi cele comerciale.

De la început au fost făcute o serie de decizii în spațiul posibilelor design-uri, care limitează aplicabilitatea, dar fac problema tractabilă. Ca oricînd în cercetarea științifică, nu este clar de la început că aceste decizii au fost cele mai bune; numai viitorul va arăta dacă această cărare este profitabilă, sau dacă rezultatele vor fi foarte specifice.

Voi discuta pe scurt unele dintre deciziile mai interesante, pentru a ilustra natura unora dintre problemele întîlnite și soluțiile oferite.

Aplicații vectoriale

Principalele aplicații care sunt ținta implementării pe PipeRench sunt cele care aplică o aceeași procesare relativ complicată asupra unui set mare de valori (unui vector). Exemple ideale: compresia, criptarea, codificarea, filtrarea de semnal, analiza statistică, etc. PipeRench va implementa atunci funcțiunea care trebuie aplicată repetat și datele vor fi trimise una cîte una spre el; la ieșire se vor culege rezultatele.

Un coprocesor master de magistrală

PipeRench are un controler special care este capabil să genereze adrese pentru magistrală pentru a citi și scrie singur din memorie. Controlerul are mai multe scopuri:

Hardware virtualizat

Probabil cea mai interesantă decizie este aceea de a ``virtualiza'' hardware-ul. Aceasta simplifică enorm scrierea de programe, pentru că utilizatorul nu mai trebuie să se preocupe de resursele disponibile. Ideea este asemănătoare cu cea de la memoria virtuală:

În felul acesta circuitul hardware ``alunecă'' (ca în figura 3) peste program. Figura ilustrează primii 6 pași din procesarea unui vector v[] de valori. Fiecare valoare a vectorului trebuie procesată de un program în 4 pași. Fiecare ``felie'' virtuală este un pas din program. Datele intră în felia 0, trec apoi prin 1, 2 și ies din 3, după care sunt scrise în memorie. Aceeași operație este aplicată tuturor elementelor din vector. Pentru figură deci m=4, n=2.

Figure 3: Funcționarea unui program pentru un circuit cu 4 ``felii'' virtuale folosind hardware real cu 2 ``felii''.
\begin{figure}\centerline{\epsfxsize=12cm\epsffile{functionare.eps}}\end{figure}

Metoda are o sumedenie de avantaje. De exemplu, atunci cînd apare un circuit mai mare pe piață, programele se vor executa mai repede, pentru că vor avea mai mult hardware la dispoziție. Nu trebuie deloc recompilate. În plus, putem executa azi (mai lent) programe pentru care nu vom avea destul hardware decît mîine.

O arhitectură ``pipe-line''

După cum vedeți fiecare felie lucrează la un moment asupra altor date de intrare; la fiecare m/n pași se produce un rezultat.

Din cauză că felia 1 este scoasă cînd apare n+1 e clar că datele pot curge numai într-o direcție în acest circuit. Acest model este asemănător cu al mașinilor ``data-flow'' (subiectul depășește cadrul acestui articol). În principiu orice aplicație poate fi adusă în această formă, dar nu orice aplicație este eficient prelucrată astfel.

Un limbaj intermediar independent de arhitectură

Pentru a ușura sarcina utilizatorilor dezvoltăm un compilator a cărui țintă este PipeRench. Există foarte puțină experiență în a scrie compilatoare pentru limbaje imperative gen C pentru astfel de mașini:

Pentru a fi relativ independent de limbajul sursă (poate va fi Java, poate C, poate ML?) și de circuitul destinație, compilatorul trebuie să folosească niște abstracții pentru hardware și limbajul surșa. Aceste abstracții trebuie să nu fie atît de generale încît să ascundă complet hardware-ul, pentru că atunci nu se poate obține eficiență.

Deocamdată compilatorul nostru ia ca sursă un limbaj intermediar special funcțional (numit DIL: Data Intermediate Language) care descrie eficace calcule pe șiruri de biți de lungimi arbitrare. Compilatorul traduce programe Dil în asamblare pentru PipeRench. ``Gaura'' dintre C și Dil este (sperăm) ceva mai ușor de umplut decît direct dintre C și asamblare; cum se face asta este subiectul cercetării viitoare.

Sculele

Iată pe scurt în figura 4 care sunt sculele pe care proiectul le-a dezvoltat și cu care experimentează tot felul de parametri arhitecturali și tehnici de compilare.

Figure 4: Sculele folosite în proiectul PipeRench
\begin{figure}\centerline{\epsfxsize=10cm\epsffile{scule.eps}}\end{figure}

Sculele hardware sunt în partea stîngă a desenului; din programe scrise în Verilog (un HDL) se poate sintetiza fie direct circuitul configurabil, fie se poate simula funcționarea circuitului.

Sculele desenate cu linie punctată încă nu există. În principiu compilarea va trece prin următorii pași:

  1. Programul sursă este partiționat în două, separînd instructîunile care vor fi efectuate folosind hardware reconfigurabil;

  2. Partea rămasă este compilată cu un compilator ordinar de C;

  3. Partea destinată circuitului reconfigurabil este tradusă în limbajul Dil;

  4. Compilatorul de Dil compilează programul, optimizează și plasează operatorii pe circuit; rezultatul este un program într-un limbaj de asamblare special pentru PipeRench;

  5. Un asamblor ia programul și generează configurația corespunzătoare.

Configurația este apoi oferită circuitului reconfigurabil (sau simulatorului), care se execută în tandem cu procesorul.

La ora aceasta o versiune preliminară a tuturor programelor desenate cu linie continuă există și este în curs de evaluare. Deși partea din stînga a figurii pare mult mai mică, este extrem de complicată, pentru că hardware-ul reconfigurabil conține circuitul propriu-zis, controlerul pentru memorie și configurare, și o interfață pentru o magistrală PCI care este în proiectare.

Concluzii

Hardware-ul reconfigurabil promite un viitor frumos, datorită capacității sale de a-și schimba funcționalitatea extrem de rapid, poate chiar în timpul funcționării. Abilitatea de a folosi operațiuni de bază extrem de simple îl face un candidat pentru a implementa procesări care în mod convențional nu se pot exprima cu ușurință. Capacitatea sa de reconfigurare îi poate da și alte atribute dezirabile, cum ar fi reziliența la erori și capacitatea de virtualizare a resurselor.

Nu mai este o dilemă dacă circuitele reconfigurabile vor intra sau nu în galeria uneltelor ordinare ale arhitectilor calculatoarelor și utilizatorilor lor. Singura întrebare este ``cînd'' se va petrece acest lucru. Răspunsul depinde numai de cei care cercetează în acest domeniu: cît de repede vor reuși să găsească optica cea mai potrivită și uneltele cele mai eficace pentru a exploata puterea expresivă a acestor circuite.



Footnotes

... atrate1
Asta are de-a face cu modul în care DRAM-ul funcționează: jumătate din biții de adrese selectează o linie, iar cealaltă jumătate din biții de adrese selectează un cuvînt de memorie din linie.
... microprocesoarele2
Această aserțiune este valabilă pentru procesoarele RISC; procesoarele CISC sunt de obicei microprogramate.
... a3
Proiectarea, descrierea și simularea de circuite hardware se face folosind o clasă specială de limbaje, numite HDL: Hardware Description Languages. Cele mai răspîndite limbaje de acest gen sunt VHDL (VLSI HDL) și Verilog.
... tiale4
Multe alte universități au proiecte de acest gen; legături spre unele dintre proiectele lor se pot găsi tot în această pagină de web.