1.1. SCHEMA BLOC A UNUI MICROSISTEM. ROLUL BLOCURILOR COMPONENTE, FUNCŢIONARE DE ANSAMBLU.

Size: px
Start display at page:

Download "1.1. SCHEMA BLOC A UNUI MICROSISTEM. ROLUL BLOCURILOR COMPONENTE, FUNCŢIONARE DE ANSAMBLU."

Transcription

1 Lucian N. VINŢAN - Organizarea si proiectarea microarhitecturilor de calcul (pentru uzul studenţilor), Universitatea L. Blaga din Sibiu, 2010, 1. O INTRODUCERE ÎN FILOSOFIA MICROSISTEMELOR DE CALCUL 1.1. SCHEMA BLOC A UNUI MICROSISTEM. ROLUL BLOCURILOR COMPONENTE, FUNCŢIONARE DE ANSAMBLU. Microprocesoarele şi, mai general, microarhitecturile de prelucrare a informaţiei (procesoarele, controlere sau chiar calculatoare sau multiprocesoare integrate pe un cip) au declanşat o adevărată revoluţie în industria calculatoarelor atât prin performanţele deosebite cât şi prin costurile tot mai diminuate, la aceeaşi putere de calcul. În multe aplicaţii, un microprocesor de vârf al zilelor noastre (2002) depăşeşte performanţele unui supercalculator de acum 10 ani, la un preţ de câteva zeci sau chiar sute de ori mai mic. În ultimii 10 ani performanţa relativă a microprocesoarelor a crescut cu cca. 60% pe an. Cercetorii susţin că cca. 65% din această creştere se datorează îmbunătăţirilor arhitecturale şi doar cca. 35% celor de natură tehnologică. Azi, la peste 20 de ani de la inventarea calculatorului personal (Apple- MacIntosh), din punct de vedere al pieţei, apar trei tipuri distincte de calculatoare. Calculatoarele personale (desktop-uri) sunt cele mai populare şi sunt destinate utilizatorilor celor mai obişnuiţi, de toate categoriile profesionale. Costă de la câteva sute de $ la cca $ în configuraţii hard-soft mai sofisticate, de tip staţii de lucru (workstations). Piaţa de PC-uri (Personal Computers) impune găsirea unor compromisuri

2 O introducere în filosofia microsistemelor de calcul 6 optimale performanţă cost. Se mai caracterizează printr-o performanţă deosebită a graficii şi capabilităţilor de conectare la Internet. La nivelul anului 2000 s-au produs cca. 150 milioane de desktop-uri. Serverele sunt destinate să ofere servicii tot mai sofisticate de reţea, inclusiv ca noduri de Internet, în locul mainframe-urilor de acum un deceniu şi mai bine. Caracteristicile lor cele mai importante se focalizează pe fiabilitate, disponibilitate, scalabilitate şi viteză de procesare. Aceste servere costă actualmente între $ şi $ (supercalculatoare) şi absorb cca. 4 milioane de microprocesoare pe an (2000). Sistemele dedicate (Embedded Systems) au dezvoltarea cea mai dinamică, estimările arătînd că la nivelul anului 2000 s-au produs cca. 300 milioane de astfel de sisteme pe an. Ele acoperă aplicaţiile cele mai frecvente(aparate foto şi camere video, comandă aparate electrocasnice, telefoane mobile, imprimante, comenzi auto, jocuri electronice, switchuri pentru reţele etc.) şi au costuri cuprinse între 10$ şi $. Multe dintre aceste sisteme au softurile scrise de producător având un grad de programabilitate relativ redus. Performanţa se focalizează pe îndeplinirea cerinţelor de timp real ale aplicaţiei. Sunt caracterizate în principal de consumuri reduse de putere (deseori sunt alimentate prin baterii şi acumulatori) şi memorii de capacităţi relativ reduse. Peste ani, aceste sisteme vor fi integrate practic în toate dispozitivele folsite de om şi interconectate prin reţeaua globală de tip Internet, conducând la conceptul de calculator omniprezent ( ubiquitous computing ). Astfel, calculatorul miniaturizat va migra de la explicitul remarcabil de azi la implicitul banal de mâine. O caracterizare globală a actualelor şi viitoarelor microarhitecturi de procesare a informaţiei necesită înţelegerea tendinţelor tehnologice şi respectiv a celor arhitecturale. În ultima perioadă de timp, prin arhitectura unui microprocesor se înţelege nu numai setul de instrucţiuni şi modurile de adresare (ISA Instruction Set Arhitecture) ci şi structura organizatorică a procesorului şi respectiv implementarea hardware a acestuia, toate aflate intr-o ierarhizare strictă. Între cele mai importante tendinţe tehnologice amintim: În cazul microprocesoarelor, gradul de integrare al tranzistorilor pe cip creşte cu cca. 55% pe an. Tehnologia de integrare a microprocesoarelor a evoluat de la 10 microni (1971) la 0,18 microni (2001). Frecvenţa ceasului creşte si ea cu cca. 50% pe an.

3 O introducere în filosofia microsistemelor de calcul 7 În cazul memoriilor DRAM, densitatea de integrare creşte cu % pe an, în timp ce timpul de acces aferent scade cu 33% pe decadă (descurajant) Densitatea informaţiei scrise pe hard-disc-uri creşte cu cca. 100% pe an, în timp ce timpul de acces aferent scade cu cca. 33% pe decadă (iarăşi descurajant) Tehnologia şi performanţele reţelelor se îmbunătăţesc semnificativ (Ethernet la 1 Gb, switch-uri ultrarapide, cablare pe fibră optică etc.) În paralel cu tendinţele mai sus menţionate, costurile scad simţitor în timp (la aceeaşi putere de calcul ori capacitate de memorare). Între cele mai importante tendinţe arhitecturale, unele analizate în continuarea acestor note de curs, amintim succint: Exploatarea paralelismului la nivelul instrucţiunilor şi firelor de execuţie, atât prin tehnici statice (soft), cât şi dinamice (hard) sau chiar hibride (cazul arhitecturii IA-64, procesorul Intel Ithanium) Structuri tot mai performante de ierarhizare a sistemului de memorie, prin utilizarea unor arhitecturi evoluate de memorie tip cache Reducerea latenţei căii critice de program, inclusiv prin tehnici de reutilizare dinamică a instrucţiunilor şi predicţie a valorilor instrucţiunilor Utilizarea multiprocesoarelor (shared memory), în special în cadrul arhitecturilor serverelor şi staţiilor grafice. De asemenea se constată o dezvoltare a sistemelor distribuite de procesare a informaţiei (message passing)

4 O introducere în filosofia microsistemelor de calcul 8 Figura 1.1. Schema bloc a unui microsistem (Microprocesor, amplificatoare de magistrale, magistrale de adrese, date comenzi şi stări, module memorie ROM şi RAM, porturi I/O lente, porturi I/O rapide interfeţe DMA, program incarcator - POST, programe BIOS) Microprocesorul este elementul central al structurii, responsabil cu aducerea din memorie, decodificarea şi execuţia instrucţiunilor maşină, codificate binar. În conformitate cu aceste instrucţiuni, microprocesorul generează secvenţiat toate semnalele (adrese, date, comenzi) necesare memoriilor şi interfeţelor pe care le gestionează. Conţine regiştri interni, unităţi de execuţie, o unitate de comandă cablată sau microprogramată, busuri interne de interconectare etc. În general este integrat pe un singur circuit. În sfera comercială, primul microprocesor, pe doar 4 biţi, s-a realizat în anul 1971 la compania Intel şi a fost proiectat de către inginerul Tedd Hoff. S-a numit Intel (În domeniul militar existau pare-se mai demult asemenea sisteme integrate complexe;, spre ex. în comanda avioanelor militare americane F14A a existat un microsistem pe 20 de biţi, cu procesare pipeline a instrucţiunilor v. Bus-ul de adrese este unidirecţional de tip tree state (TS). Prin intermediul acestui bus microprocesorul pune adresa de acces la memorie sau la porturile I/O (Input/Output). Lumea externă a microprocesorului este

5 O introducere în filosofia microsistemelor de calcul 9 constituită exclusiv din memorie şi interfeţele de intrare ieşire. Acestea sunt resursele care pot fi accesate (scrise respectiv citite) de către microprocesor. Aşadar, acesta nu vede în mod direct perifericele ci doar prin intermediul interfeţelor de I/O. Bus-ul de date este de tip bidirecţional TS. Prin intermediul acestui bus microprocesorul aduce din memorie instrucţiunea, respectiv citeşte data (operandul) din memorie sau dintr-un port de intrare (arhitectura Princeton de memorie). La scriere microprocesorul plasează pe bus-ul de date rezultatul pe care doreşte să-l scrie în memorie sau într-un port de ieşire. La citire, rezultatul este preluat prin intermediul acestui bus din memorie sau dintr-un port de intrare. În ambele cazuri, microprocesorul activează adresa respectivă pe bus-ul de adrese împreună cu semnalele de comandă aferente (Read, Write, Memorie, Interfaţă etc.) pe bus-ul de comenzi. Pe bus-ul de stări, dispozitivele slave (memorii, interfeţe) comunică informaţii referitoare la modul de desfăşurare al transferului (Ex. semnalul aşteaptă, emis spre microprocesor, cu semnificaţia că transferul de date comandat nu este încă încheiat). Memoria poate fi văzută intr-o primă abordare ca o stivă de locaţii binare (cuvinte), fiecare cuvânt fiind caracterizat de o adresă binară unică. Figura 1.2. Schemă generică de memorie

6 O introducere în filosofia microsistemelor de calcul 10 În general M=8,16,32,64<=> largime bus date microprocesor (microsistem pe M biti) Memoria este caracterizatã prin 2 parametri de bazã: - capacitatea (nr. de locaţii pe care le conţine) - latenţa (timpul de acces) care este o caracteristicã intrinsecã a circuitului de memorie si reprezintã in principiu timpul scurs din momentul furnizãrii adresei de cãtre microprocesor pânã in momentul in care memoria a încheiat operaţia comandatã (citire sau scriere). Fireste, se doresc capacităţi cât mai mari si latente cât mai mici, cerinţe în general contradictorii. Figura 1.3. Un ciclu (fază) extern de citire din memorie Între busul de adrese si memorie exista un decodificator N:2 N ca în figură:

7 O introducere în filosofia microsistemelor de calcul 11 Figura 1.4. Decodificator N:2 N N Sel0 = NADR0* NADR1*...* NADR(2 1).. N N Sel(2 2) = ADR0* ADR1*...* ADR(2 2) * NADR(2 N N Sel(2 1) = ADR0* ADR1*...* ADR(2 1) N 1) Cu 10 biţi de adrese => 2 10 cuvinte = 1k cuvânt (kilo) Cu 20 biţi de adrese => 2 20 cuvinte = 2 10 k cuvânt = 1M cuvânt (mega) Cu 30 biţi de adrese => 2 30 cuvinte = 2 10 M cuvânt = 1G cuvânt (giga) Cu 40 biţi de adrese => 2 40 cuvinte = 2 10 G cuvânt = 1T cuvânt (terra) M = 8 => 1 cuvânt = 1 octet Dintr-un punct de vedere tehnologic memoriile se împart: ROM (Read Only Memory) EPROM, EEPROM RAM (Random Acces Memory) - SRAM (static) - DRAM (dinamic) Memoriile EPROM sunt memorii rezidente care păstrează conţinutul şi după decuplarea tensiunii de alimentare. Ele sunt reprogramabile în sensul în care pot fi şterse prin expunere la raze ultraviolete şi reînscrise pe baza unui dispozitiv special numit programator de EPROM uri.

8 O introducere în filosofia microsistemelor de calcul 12 EPROM-urile păstrează aşa numitul program monitor înscris de către fabricant care este primul program procesat de către sistem imediat după alimentarea (resetarea) sa. Acest lucru este absolut necesar întrucât conţinutul memoriilor RAM este neprecizabil imediat după alimentare. Prin urmare, imediat după RESET conţinutul PC-ului este iniţializat şi va pointa spre prima instrucţiune din programul monitor rezident în EPROM.Rolul programului monitor este de a efectua o testare sumară a microprocesorului şi a celorlalte componente ale microsistemului, după care va iniţia încărcarea sistemului de operare (Linux, Windows etc.) de pe disc în memoria RAM. După aceasta programul monitor dă controlul sistemului de operare rezident acum în RAM. De asemenea ROM-ul conţine rutinele de intrare ieşire BIOS. SRAM: sunt memorii deosebit de rapide, timp de acces de t 0 = 1 ns 15 ns, având capacitate de integrare redusă (sute de Ko per circuit). DRAM: constituie peste 95 % din memoria oricărui sistem de calcul de uz general datorită faptului că oferă densităţi mari de integrare (64 Mbiţi 256 Mbiţi / chip) şi timpi de acces relativ rezonabili t 0 =30 ns 60 ns. Totuşi, decalajul între timpul de acces ridicat al acestor memorii şi viteza mare de execuţie a microprocesorului, constituie una dintre marile probleme tehnologice şi arhitecturale în ingineria calculatoarelor. Fiind realizate în tehnologie MOS puterea absorbită este redusă. Din păcate au 2 mari dezavantaje: 1. Accesare (citire / scriere) complicată. Circuitele DRAM sunt organizate sub o formă matricială, pe linii şi coloane. Bitul ce se doreşte a fi accesat se află la intersecţia liniei cu coloana selectată. Un circuit DRAM are următoarele terminale (pini):

9 O introducere în filosofia microsistemelor de calcul 13 Figura 1.5. Circuit DRAM RAS (Row Address Strobe strob adresă rând), CAS (Column Address Strobe strob adresă coloană) Figura 1.6. Ciclul de citire din DRAM Pentru o citire corectă este necesar ca frontul căzător al lui RAS să strobeze perfect adresa de rând (o memorează într-un registru intern al circuitului) iar frontul căzător al lui CAS să strobeze perfect adresa de coloană. În momentul memorării adresei de coloană (căzătorul lui CAS) memoria are toate elementele necesare furnizării bitului de ieşire Dout, după un timp precizat în catalog (de cca. 20 ns la memoriile 4164). Rezultă deci că interfaţa între microprocesor şi DRAM este complicată întrucât din semnalele pe care le furnizează microprocesorul (adresă de memorie şi

10 O introducere în filosofia microsistemelor de calcul 14 comandă), interfaţa trebuie să fabrice protocolul mai sus expus (secvenţa ADR, RAS, CAS ). 2. Necesitatea regenerării memoriei DRAM. Bitul de informaţie DRAM este implementat sub forma unui condensator. Din păcate acest condensator se descarcă în timp şi prin urmare cu timpul poate să piardă informaţia pe care o memorează => deci că periodic el trebuie reîncărcat (refresh, regenerare). Regenerarea se face pe întreg rândul din matricea de memorare. Conform catalogului un anumit rând ţine minte informaţia circa 2 ms. După acest interval, întreg rândul trebuie regenerat. Algoritmul de regenerare va trebui să fie unul de tip secvenţial care să regenereze rând după rând în mod ordonat. Rezultă că rata de regenerare a 2 rânduri succesive i respectiv (i+1) trebuie să se facă la un interval de maxim 2 ms/n, unde N=nr. de rânduri al circuitului de memorie DRAM. De exemplu, considerând N=128 rânduri (DRAM 4116, 4164) => rata de regenerare 2 ms/128 ~ 15,6 µs. Prin urmare vom avea accese la DRAM din 2 părţi: din partea µprocesorului care citeşte / scrie conform programului pe care îl execută din partea unui automat de regenerare care regenerează periodic, rând după rând, memoria DRAM. Posibilele conflicte la memoria DRAM între microprocesor şi automatul de regenerare vor trebui gestionate corespunzător, eventual acceptând chiar prin blocaje reciproce, rezultând scăderea performanţei. Ar fi utilă implementarea unei "regenerari transparente" (care sa nu blocheze deloc procesorul). Acest deziderat necesită compromisuri între viteza de procesare şi gradul de transparenţă al regenerării. Standardizarea bus-urilor şi a protocoalelor aferente a condus la conceptul fecund de microsistem de dezvoltare. Într-un asemenea microsistem, prin simpla conectare la bus-ul comun (date, adrese, comenzi, stări) standard a unor noi module compatibile (memorii, interfeţe) se permite o dezvoltare în timp a microsistemului iniţial. Spre exemplu, cunoscutele microsisteme standardizate de tip IBM PC, constituie astfel de sisteme de dezvoltare construite în jurul unor magistrale standardizate. Cam cât timp durează procesarea unei instrucţiuni?

11 O introducere în filosofia microsistemelor de calcul 15 Exemplu: instrucţiunea ADD reg1,(reg2)200, codificată pe un singur cuvânt egal cu lărgimea de bandă a interfeţei procesor memorie. Semantica: reg1 (reg1) + cuv. mem adr.(reg2) fclk = 100MHz TCLK = = 10ns fclk Timpul de acces DRAM : tadram = 70 ns Această instrucţiune se procesează, conform modelului secvenţial clasic (atribuit marelui matematician american John von Neumann autorul primului document referitor la un calculator electronic numeric pe deplin funcţional), în faze succesive, după cum urmează: Faza IF (instruction fetch): ciclu de citire din memorie de la adresa dată de PC (program counter) durează aproximativ, spre ex., 10 T CLK (conf. protocolului unui ciclu mediu de acces la memorie) = 100 ns. Faza ID (instruction decode): în această fază microprocesorul decodifică instrucţiunea ( înţelege ce trebuie să facă ]n continuare) şi ca urmare aduce într-un registru temporar intern, situat la intrarea ALU, operandul din reg1. Decodificarea instrucţiunii consumă uzual 1T CLK = 10ns. Calcul adresă memorie a celui de-al doilea operand (reg2) ADR (BUS) atacă memoria: ~ 1 T CLK =10 ns. Declanşare ciclu de aducere a operandului din memorie de la adresa anterior calculată. Durează, ca şi IF, ~ 10 T CLK = 100 ns. Faza EX: execuţia propriu-zisă a instrucţiunii, adunarea celor 2 operanzi, durează ~ 1 T CLK = 10 ns => timpul de procesare aferent acestei instrucţiuni T~250 ns => nr. de instrucţiuni pe secundă:~ instrucţiuni sec. (4 MIPS) (Pentium I ~ 15 MIPS) De remarcat faptul că o instrucţiune se procesează sub forma unei înlănţuiri de cicli maşină (faze). Un ciclu maşină reprezintă o înlănţuire de acţiuni sincronizate cu un impuls de tact. Ciclul maşină este unitatea atomică de procesare, cea care nu poate fi întreruptă de nici o cerere externă. Obs.: Utilitatea modurilor de adresare indirecte prin registru şi indexate (adresa operand din memorie = R+index) este dată de facilitatea scrierii compacte a programelor (bucle), adresării elegante a unor structuri de date de tip tablou situate în memorie etc. Astfel de structuri de date se întâlnesc implementate atât în cadrul limbajelor de nivel înalt (ex. în limbajul C, stiva de date asociată unei funcţii şi care trebuie accesată în vederea transmiterii de parametri respectiv revenire dintr-un apel) cât şi al aplicaţiilor scrise în aceste limbaje.

12 O introducere în filosofia microsistemelor de calcul 16 Harta de memorie a unui microsistem. Ex. Să se proiecteze un sub-sistem de memorie având 16 KO de ROM incepând cu adresa 0, implementați cu cipuri de 4 KO și, în continuarea ROM, 32 KO SRAM implementați cu cipuri de 8 KO MODURI DE LUCRU ÎNTRE MICROPROCESOR ŞI INTERFEŢELE I/O MODUL DE LUCRU PRIN INTEROGARE ( POLLING ) Se bazează pe testarea de către microprocesor a unui bit de stare asociat dispozitivului periferic. Microprocesorul nu va iniţializa transferul cu perifericul decât în momentul în care bitul de stare semnifică faptul că perifericul este pregătit pentru transfer (nu lucrează la un transfer iniţiat anterior). Să considerăm de exemplu interfaţa cu o tastatură. Această interfaţă trebuie să conţină minimum 2 registre. RBuff va memora un octet care reprezintă codul ASCII (Unicode) al tastei apăsate de către utilizator. Exemple: A = 41h a = 61h = 30h = 20h Bitul Ready din registrul de stare este un bit de tip Read Only cu următoarea semnificaţie: dacă registrul RBuff se încarcă cu un octet

13 O introducere în filosofia microsistemelor de calcul 17 (utilizatorul a apăsat o tastă) atunci Ready se pune automat pe 1 arătând microprocesorului că poate să preia codul din RBuff. Bitul Ready se va reseta automat odată cu preluarea codului din Rbuff de către microprocesor. Un program - absolut principial - de gestiune a tastaturii s-ar scrie ca mai jos: Dezavantajul acestei metode constă în faptul că microprocesorul aşteaptă un timp T, neacceptabil de mare la nivelul vitezei sale, pentru a inspecta dacă perifericul este sau nu este pregătit. Considerând că utilizatorul apasă o tastă la interval de 500 ms şi că o instrucţiune a microprocesorului durează cca. 250 ns (vezi justificarea anterioară) => că pierde 500 ms / 250 ns = 2 milioane instrucţiuni în bucla de aşteptare în loc să execute instrucţiuni utile. Acest dezavantaj este eliminat de metoda următoare de comunicare procesor-interfaţă: MODUL DE LUCRU PRIN ÎNTRERUPERI HARDWARE Se bazează pe generarea unui semnal de întrerupere INT de la interfaţă (port) spre microprocesor ori de câte ori acesta doreşte un serviciu de la microprocesor. Ca urmare a recepţionării semnalului INT microprocesorul va abandona programul principal (PP) urmând să intre intr-o aşa numită rutină tratare a întreruperii în care va satisface cererea interfeţei. La finele rutinei de tratare a întreruperii printr-o instrucţiune de tip RETURN, microprocesorul va reveni in PP, in general dar nu întotdeauna, pe instrucţiunea imediat următoare ultimei instrucţiuni din PP executate. In cazul exemplului cu tastatura anterior considerat, interfaţa va genera întreruperea INT ori de câte ori utilizatorul a apăsat o tastă, adică registrul

14 O introducere în filosofia microsistemelor de calcul 18 RBuff este plin, deci conţine codul (ASCII, Unicode etc.) al caracterului tastat. Figura 1.7. Modelul de lucru prin întreruperi Aşadar RTI după ce execută serviciul necesar perifericului (în cazul acesta preluare şi depozitare caracter în memorie) revine în PP, unde până când perifericul cere un nou serviciu (de ex. se apasă din nou o tastă), microprocesorul va executa instrucţiuni utile din PP (sistem de operare, program utilizator etc.) si deci nu mai este necesar să mai aştepte inutil ca in cazul 1. Totalitatea acţiunilor executate de către microprocesor din momentul apariţiei semnalului de întrerupere INT până în momentul procesării primei instrucţiuni din RTI formează aşa numitul protocol hardware de acceptare a întreruperii (săgeţile 1 şi 3 din figură). În principiu acest protocol se desfăşoară în următoarele etape succesive: 1.) Odată sesizată întreruperea INT de către microprocesor acesta îşi va termina instrucţiunea in curs de execuţie după care, dacă anumite condiţii sunt îndeplinite (nu există activată o cerere de întrerupere sau de bus mai prioritare etc.), va trece la pasul 2. În general, microprocesoarele examinează activarea întreruperilor la finele ultimului ciclu aferent instrucţiunii în curs de execuţie. 2.) Recunoaşterea întreruperii: microprocesorul va iniţializa aşa numitul ciclu de achitare a întreruperii. Pe parcursul acestui ciclu extern va genera un semnal de răspuns (achitare) a întreruperii INTACK (interrupt acknowledge) spre toate interfeţele de intrare - ieşire. Ca urmare a recepţionării INTACK interfaţa care a întrerupt va furniza

15 O introducere în filosofia microsistemelor de calcul 19 microprocesorului prin intermediul bus-ului de date un aşa numit octet vector de întrerupere (VI). Acest VI este diferit pentru fiecare periferic în parte, individualizându-l deci într-un mod unic. Pe baza acestui VI şi conform unui algoritm care diferă de la microprocesor la microprocesor, acesta va determina adresa de început a RTI, adresă ce va urma să o introducă in PC. Fireşte, la VI diferiţi vor corespunde adrese de început diferite. 3.) Microprocesorul va salva într-o zonă specială de program numită memorie stivă, PC-ul aferent instrucţiunii imediat următoare instrucţiunii executate de către microprocesor din PP (PCrev), pentru a putea şti la finele RTI unde să revină exact în PP. Memoria stivă este o zonă de memorie RAM caracterizată la un moment dat de aşa numitul vârf al stivei adică de ultima locaţie ocupată din stivă. Acest vârf al stivei este pointat (adresat) permanent de conţinutul unui registru special dedicat, existent în orice microprocesor modern, numit SP (stack pointer). În memoria stivă sunt posibile 2 tipuri de operaţii: operaţia PUSH Reg care se desfăşoară astfel: SP (SP) 1( cuvânt = octet) (Reg) Mem adr.sp operaţia POP Reg: (Reg) Mem adr.sp SP (SP) +1 Figura 1.8. Modul de lucru al stivei Stiva este o memorie de tip LIFO (last in first out) si care spre deosebire de PC în procesarea secvenţială, "creşte" (PUSH) de obicei înspre adrese descrescătoare evitându-se astfel suprapunerea zonelor de program (cod) cu cele de stiva.

16 O introducere în filosofia microsistemelor de calcul 20 4.) Intrarea în RTI se face simplu prin introducerea adresei de început a RTI calculată in pasul 2, in registrul PC. Normal în continuare microprocesorul va aduce şi executa prima instrucţiune din RTI protocolul de tratare fiind în acest moment încheiat şi controlul fiind preluat de RTI a perifericului care a fost întrerupt. După cum s-a observat protocolul de tratare salvează in stiva doar PC-ul de revenire (la anumite microprocesoare se mai salvează registrul de stări - flags). Acest fapt se poate dovedi insuficient având în vedere că in cadrul RTI pot fi alteraţi anumiţi regiştri interni ai microprocesorului. Această alterare a regiştrilor poate fi chiar catastrofală la revenirea în PP. Din acest motiv cade in sarcina celui care scrie RTI să salveze (instrucţiuni PUSH) respectiv să returneze corespunzător (instrucţiuni POP) aceşti regiştri. Figura 1.9. Efectul RTI asupra stivei Acţiunea instrucţiunii RETURN este echivalentă cu o operaţie de tip POP PC. a) PC Mem adrsp RET : b) SP SP + 1 Acum devine evident de ce instrucţiunea RETURN implementează revenirea în PP pe instrucţiunea imediat următoare celei întrerupte. Obs.: Prin mecanismul de stivă se pot gestiona perfect şi întreruperile de tip imbricat (apariţia unei întreruperi INT în chiar rutina de tratare a altei întreruperi, când este permis).

17 O introducere în filosofia microsistemelor de calcul MODUL DE LUCRU PRIN TRANSFER DMA (DIRECT MEMORY ACCESS) Există dispozitive periferice a căror rată de transfer (octeţi /secundă) este atât de ridicată încât, din motive de timing, face imposibil modul de lucru prin întreruperi. Astfel de exemplu discurile magnetice şi interfeţele video, impun rate de transfer de 4-20 Mo /s rezultând 1 octet la 250 ns până la 50 ns. Este evident că, fără un buffer FIFO (First In First Out) între periferic şi memorie, transferul prin întreruperi este imposibil în acest caz întrucât rata de transfer este comparabilă cu durata unei instrucţiuni a microprocesorului. Aşadar, în aceste cazuri durata RTI ar fi mult mai mare decât rata de transfer a perifericului (octeţi per secundă). Un monitor video este un alt periferic rapid de vreme ce, pe durata unei curse directe a baleiajului pe orizontală a spotului de câteva zeci de microsecunde, trebuie afişate zeci sau chiar sute de octeţi (caractere). De aceea în aceste cazuri se impune un transfer direct între memorie şi dispozitivul periferic. Figura Modul de lucru prin transfer DMA Atunci când se doreşte prin program transferul unor octeţi din memorie pe disc sau citirea de pe disc în memorie microprocesorul va scrie în interfaţa DMA aferentă (prin instrucţiuni de tip OUT succesive) următoarele informaţii: - adresa de început de pe disc (nr. cilindru, nr. cap, nr. sector). Header reprezintă adresa de început sector, deci un identificator al sectorului care se scrie la formatarea fizică a discului

18 O introducere în filosofia microsistemelor de calcul 22 Figura Structura discului magnetic - adresa de început a zonei de memorie (RAM) utilizată în transfer - nr. octeţi (sectoare) care trebuiesc transferate - sens transfer (Write sau Read pe / de pe disc) În urma recepţionării acestor informaţii interfaţa DMA va activa un semnal numit cerere de bus (HOLD) spre microprocesor. Ca urmare a recepţionării semnalului HOLD, la finele ciclului maşină în curs (reamintesc, ciclul este unitate atomică de procesare!) microprocesorul îşi va pune bus-urile de adrese date şi comenzi in TS permiţând astfel controlul acestora de către DMA (EN1=1, microprocesor master pe bus, EN2=1, DMA master pe bus). Simultan microprocesorul va activa semnalul de răspuns la HOLD numit semnal de achitare a cererii (HLDA). Ca urmare a recepţionării achitării HLDA (Hold Acknowledge), DMA-ul va starta transferul efectiv între disc şi memorie având toate informaţiile necesare pentru aceasta. Spre exemplu, dacă s-a comandat citire de pe disc (scriere în memorie) DMA-ul va adresa memoria pe bus-ul de adrese simultan cu punerea pe bus-ul de date a cuvântului (octetului) scris în memorie. La finele transferului DMA interfaţa va dezactiva semnalul HOLD, ca urmare microprocesorul, dezactivând şi el semnalul HLDA, îşi va continua activitatea întreruptă prin

19 O introducere în filosofia microsistemelor de calcul 23 procesarea următorului ciclu maşină. O cerere de bus (HOLD) este prioritară faţă de o cerere de întrerupere (INT). De remarcat că diferenţa de principiu între transferurile prin interogare - întreruperi şi respectiv transferul DMA constă în faptul că în cazul primelor două transferul se face programat, prin intermediul microprocesorului care serveşte perifericul în cadrul rutinei de tratare, pe când în cazul DMA se face fără intervenţia microprocesorului, direct între memorie şi interfaţa DMA. Pe timpul HLDA=1, microprocesorul îşi întrerupe orice activitate externă, master pe bus fiind DMA-ul. Un sistem de calcul cu DMA este un arhetip al sistemelor multiprocesor. Tipuri de interfețe (porturi) Porturi (interfețe) paralele Figura Cronograma unui transfer DMA Facilitează transferul de date între memoria microprocesorului (microcontrolerului calculator pe un singur cip. Conține CPU, memorie si interfețe I/O. Este destinat controlului în timp real a unor procese.) și dispozitivele periferice prin intermediul unor magistrale paralele (transfer simultan al mai multor biți). Sens transfer input sau output. Transferul se face de obicei prin intermediul unor protocoale asincrone de tip handshake (intrebare-răspuns; vezi spre ex. modul de lucru prin interogare). Exemplu generic protocol handshake: Activare Adresă Port In (MP), Activare Comandă Read - de la microprocesor (MP), Wait (eventual), Read_Ack de la interfață (periferic) + Activare și Citire

20 O introducere în filosofia microsistemelor de calcul 24 Date - de la interfață, Dezactivare Comandă Read, Dezactivare Read_Ack, Dezactivare Date (periferic), Dezactivare Adresă Port In (MP). O magistrală caracterizată de protocolul de transfer aferent Porturi seriale Transfer serial asincron (Universal Asynchronous Receiver Transmitter UART) START (1 bit activ pe 0), DATE (5-8 biți), PARITATE (parăimpară), STOP (1-2 biți activi pe 1) Este necesar ca durata unui bit să fie aceeași la Emițător și la Receptor (ex. 600, 1200, 2400, 4800, 9600 bps) Emisie: buffer emisie gol (empty) se poate înscrie un nou cuvânt de date (paralel), care va fi serializat de către UART Recepție: buffer recepție plin (full) trebuie citit cuvântul asamblat de UART din buffer (conține doar datele) UART cuvintele se transmit-recepționează asincron chiar dacă biții din cadrul unui cuvant sunt, evident, sincroni. Timere Oferă funcții de timp (real). Obligatoriu la microcontroler (MC). Măsoara timpul (ex. bucle de întârziere) și generează semnale de diferite frecvențe (spre ex. pe post de întreruperi de timp real comutare între aplicații, startare secvență periodică de program etc.). Spre ex. programatorul setează un registru timer cu o anumită valoare. Acesta este decrementat cu un semnal de frecvență cunoscută. Când conținutul acestui registru este zero se generează o întrerupere etc. Alt ex.: măsoară perioada unui semnal (nr. impulsuri timer între 2 fronturi crescătoare succesive ale semnalului) Funcție watchdog un numărător intern MC care este activat prin soft. Când ajunge la valoarea maximă resetează sistemul. Ca să nu se întâmple asta, programatorul trebuie să-l încarce înainte de resetare. Util în depanare (detecție eroare de program). Module PWM (Pulse Width Modulation)

21 O introducere în filosofia microsistemelor de calcul 25 Folosit la comanda motoarelor de c.c., comanda surselor de alimentare etc. Generat periodic, fără intervenția CPU. Perioadă (T), factor de umplere (T 1 /T) se poate modifica în mod controlat prin soft. Module A/D și D/A Practic obligatoriu la microcontroler (MC). Timpi conversie 8-20 micosecunde. Semnalul analogic trebuie menținut constant pe durata conversiei. (Circuite de eșantionare/memorare). Rezoluții 8-12 biți. Tensiunea dereferință, GND. Declanșarea și terminarea conversiei sunt semnalizate prin biți de control. Rezultatul conversiei este memorat într-un registru de date. Se pot genera întreruperi la finele procesului. Declanșarea conversiei poate fi internă (prin soft) sau externă (ex. prin timer) Controler de întreruperi Arbitrează cererile (priorități fixe - PF, rotitoare Round Robin) Generează INTACK și vectori de întrerupere pentru fiecare nivel de cerere (Interrupt Request Level) Poate masca anumite cereri. Demascare. Ex. în modul PF, întreruperea de un anumit nivel poate bloca toate cererile mai puțin prioritare la finele rutinei de tratare (RTI), trebuie demascate (prin scrierea intr-un registru special al controlerului). În general, RTI aferentă unei întreruperi poate fi întreruptă de o cerere mai prioritară. A nu se uita însă demascarea întreruperii mai puțin prioritare la finele rutinei celei mai prioritare.

22 2. ARHITECTURA SISTEMULUI IERARHIZAT DE MEMORIE [8] 2.1. MEMORII CACHE Cache: a safe place for hiding or storing things. (Webster s New World Dictionary of the American Language, Third College Edition ) Memoria cache este o memorie situată din punct de vedere logic între CPU (Central Processing Unit - unitate centrală) şi memoria principală (uzual DRAM - Dynamic Random Access Memory), mai mică, mai rapidă şi mai scumpă (per byte) decât aceasta şi gestionată în general prin hardware astfel încât să existe o cât mai mare probabilitate statistică de găsire a datei accesate de către CPU, în cache. Aşadar, cache-ul este adresat de către CPU în paralel cu memoria principală (MP): dacă data dorită a fi accesată se găseşte în cache, accesul la MP se abortează, dacă nu, se accesează MP cu penalizările de timp impuse de latenţa mai mare a acesteia, relativ ridicată în comparaţie cu frecvenţa de tact a CPU. Oricum, data accesată din MP se va introduce şi în cache. Memoriile cache sunt implementate în tehnologii de înaltă performanţă, având deci un timp de acces foarte redus dacă sunt integrate în microprocesor (cca. 1 5 ns la ora actuală). În prezent presiunea asupra acestor memorii este foarte ridicată, rolul lor fiind acela de a apropia performanţa microprocesoarelor (care creşte cu cca % pe an) cu aceea a memoriilor DRAM, a căror latenţă scade cu doar cca. 7 % pe an. În general, pentru a accesa o locaţie DRAM, un procesor pierde de impulsuri de tact (~ timp acces DRAM / T CLK, T CLK = perioada ceasului microprocesorului), în schimb accesarea cache-ului se face în doar 1 3 impulsuri de tact. Cu alte cuvinte, memoria cache reduce timpul mediu de acces al CPU la MP, ceea ce este foarte util. Se defineşte un acces al CPU cu hit în cache, un acces care găseşte o copie în cache a datei accesate. Un acces cu miss în cache este unul care nu găseşte o copie în cache a datei accesate de către CPU şi care, prin urmare,

23 Arhitectura sistemului ierarhizat de memorie 27 adresează MP cu toate penalizările de timp care derivă din accesarea acesteia. Se defineşte ca parametru de performanţă al unei memorii cache rata de hit, ca fiind raportul statistic între numărul acceselor cu hit în cache respectiv numărul total al acceselor CPU la memorie. Măsurat pe benchmark-uri (programe de test) reprezentative, la ora actuală sunt frecvente rate de hit de peste 90 %. Rata de miss (RM) este complementara ratei de hit (RH), astfel că: RH [%] + RM [%] = 100 %. În esenţă, utilitatea cache-ului derivă din următorul fapt: la o citire cu miss (din MP), data adusă din MP este introdusă şi în cache, în speranţa că la o următoare citire a aceleiaşi date, aceasta se va găsi în cache (hit). În realitate, în cazul unei citiri cu miss în cache se aduce din MP nu doar data (cuvântul) dorită de către CPU ci un întreg bloc (4 16 cuvinte) care evident conţine data respectivă. O citire cu miss presupune aducerea blocului din MP dar înainte de aceasta se impune evacuarea în MP a unui bloc din cache. Aşadar, transferul din cache în MP se face tot la nivel de bloc şi nu de cuvânt. Astfel, se optimizează traficul între cache şi MP pe baza a 2 principii care vor fi discutate în continuare. În esenţă, eficienţa memoriilor cache se bazează pe 2 principii de natură statistică şi care caracterizează intrinsec noţiunea de program: principiile de localitate temporală şi spaţială. Conform principiului de localitate (vecinătate) temporală, există o mare probabilitate ca o dată (instrucţiune) accesată acum de către CPU să fie accesată din nou, în viitorul imediat. Conform principiului de localitate spaţială, există o mare probabilitate ca o dată situată în imediata vecinătate a unei date accesate curent de către CPU, să fie şi ea accesată în viitorul apropiat (pe baza acestui principiu statistic se aduce din MP în cache un întreg bloc şi nu doar strict cuvântul dorit de către CPU). O buclă de program structură esenţială în orice program exemplifică foarte clar aceste principii şi justifică eficienţa conceptului de cache. O combinare a celor 2 principii anterior expuse conduce la celebra regulă 90/10 care spune că cca. 90 % din timpul de rulare al unui program se execută doar cca. 10 % din codul acestuia. Personal, credem că mai puţin. Pe baza acestor principii empirice se situează întreg eşafodajul conceptului de cache; eficienţa sa deosebită nu poate fi explicată prin considerente analitice pentru simplul fapt că este practic imposibil a descrie analitic noţiunea de program. În fond, ce este un program? Care este distribuţia instrucţiunilor sau a primitivelor structurale într-un program? Poate fi aceasta descrisă concret, pe baza unor modele deterministe sau aleatoare? Dificultatea unor răspunsuri exacte la aceste întrebări dată în fond de imposibilitatea punerii în ecuaţie a minţii umane, cea care creează infinita

24 Arhitectura sistemului ierarhizat de memorie 28 diversitate de programe face ca cea mai bună explicaţie asupra eficienţei memoriilor cache să stea în cele 2 principii empirice anterior schiţate, caracterizând intrinsec noţiunea de program. Din punct de vedere arhitectural, există 3 tipuri distincte de memorii cache în conformitate cu gradul de asociativitate: cu mapare directă, semiasociative şi total asociative. Figura 2.1. Scheme de mapare în cache La cache-urile cu mapare directă, ideea principală constă în faptul că un bloc din MP poate fi găsit în cache (hit) într-un bloc unic determinat. În acest caz regula de mapare a unui bloc din MP în cache este: (Adresa bloc MP) modulo (Nr. blocuri din cache) Stricteţea regulii de mapare conduce la o simplitate constructivă a acestor memorii dar şi la fenomenul de interferenţă al blocurilor din MP în cache. Astfel, de exemplu, blocurile 12, 20, 28, 36, 42 etc. nu pot coexista în cache la un moment dat întrucât toate se mapează pe blocul 4 din cache. Prin urmare, o buclă de program care ar accesa alternativ blocurile 20 şi 28 din MP ar genera o rată de hit egală cu zero. La cache-urile semiasociative există mai multe seturi, fiecare set având mai multe blocuri componente. Aici, regula de mapare precizează strict doar setul în care se poate afla blocul dorit, astfel: (Adresa bloc MP) modulo (Nr. seturi din cache) În principiu blocul dorit se poate mapa oriunde în setul respectiv. Mai precis, la un miss în cache, înainte de încărcarea noului bloc din MP, trebuie evacuat un anumit bloc din setul respectiv. În principiu, în mod uzual, există implementate două-trei tipuri de algoritmi de evacuare: pseudorandom (cvasialeator, uşor de implementat), FIFO (sau round-robin, se evacuează

25 Arhitectura sistemului ierarhizat de memorie 29 blocul cel mai vechi din cache. Contorul aferent se încarcă doar la încărcarea blocului în cache şi nu la fiecare hit per bloc, ca la algoritmul LRU) şi LRU ( Least Recently Used ). Algoritmul LRU evacuează blocul din cache cel mai de demult neaccesat, în baza principiului de localitate temporală (aflat oarecum în contradicţie cu o probabilistică markoviană care ar sugera să fie păstrat!). În practică, implementările FIFO, LRU sunt simplificate şi deci aproximative. Deşi acest model pare intuitiv corect, el poate genera şi rezultate eronate uneori. De exemplu, numărul total de accese cu miss poate uneori să crească când creşte asociativitatea, iar politica de înlocuire LRU este departe de a fi cea optimă pentru unele din programe.această anomalie poate fi evitată prin folosirea algoritmului optim (OPT) în loc de LRU ca bază pentru clasificarea miss-urilor în cache. Algoritmul OPT, înlocuieşte întotdeauna blocul care va fi adresat cel mai târziu în viitor (eventual nu va mai fi adresat deloc). Un astfel de algoritm s-a dovedit a fi cvasi-optimal pentru toate pattern-urile de program, ratele de miss fiind cele mai mici în acest caz, dintre mai toate politicile de înlocuire folosite. Politica se dovedeşte optimă doar pentru fluxuri de instrucţiuni read-only. Pentru cache-urile cu modalitate de scriere writeback algoritmul de înlocuire nu este întotdeauna optim (spre exemplu poate fi mai costisitor să se înlocuiască blocul cel mai târziu referit în viitor dacă blocul trebuie scris şi în memoria principală,fiind "murdar", faţă de un bloc "curat" referit în viitor puţin mai devreme decât blocul "murdar" anterior; în plus, blocul curat nu mai trebuie evacuat, ci doar supra-scris). Este evident un algoritm speculativ, practic imposibil de implementat în practică. Totuşi el are două calităţi majore: (1) reprezintă o metrică de evaluare teoretică a eficenţei algoritmului de evacuare implementat în realitate, absolut necesară şi (2) induce ideea fecundă a predictibilităţii valorilor de folosinţă ale blocurilor din cache, conducând astfel la algoritmi predictivi rafinaţi de evacuare (revezi memoria SVC, care implementează un astfel de algoritm). Dacă un set din cache-ul semiasociativ conţine N blocuri atunci cacheul se mai numeşte tip N-way set associative. Mai nou, se implementează algoritmi de evacuare predictivi, care anticipează pe baze euristice utilitatea de viitor a blocurilor memorate în cache, evacuându-l pe cela mai puţin valoros. Deşi aceşti algoritmi depăşesc în mod normal cadrul acestui curs de iniţiere în domeniul microprocesoarelor, în continuare se va prezenta totuşi unul, integrat în arhitectura numită Selective Victim Cache. Este evident că într-un astfel de cache rata de interferenţă se reduce odată cu creşterea gradului de asociativitate (N mare ). Aici, de exemplu, blocurile 12, 20, 28 şi 36 pot coexista în setul 0. Prin reducerea posibilelor interferenţe ale blocurilor, creşterea gradului de asociativitate determină

26 Arhitectura sistemului ierarhizat de memorie 30 îmbunătăţirea ratei de hit şi deci a performanţei globale. Pe de altă parte însă, asociativitatea impune căutarea după conţinut (se caută deci într-un set dacă există memorat blocul respectiv) ceea ce conduce la complicaţii structurale şi deci la creşterea timpului de acces la cache şi implicit la diminuarea performanţei globale. Optimizarea gradului de asociativitate, a capacităţii cache, a lungimii blocului din cache etc., nu se poate face decât prin laborioase simulări software, variind toţi aceşti parametrii în vederea minimizării ratei globale de procesare a instrucţiunilor [instr./cicli]. În fine, memoriile cache total asociative, implementează practic un singur set permiţând maparea blocului practic oriunde în cache. Ele nu se implementează deocamdată în siliciu datorită complexităţii deosebite şi a timpului prohibit de căutare. Reduc însă (practic) total interferenţele blocurilor la aceeaşi locaţie cache şi constituie o metrică superioară utilă în evaluarea ratei de hit pentru celelalte tipuri de cache-uri (prin comparaţie). Cele 3 scheme următoare prezintă implementări realizate pentru tipurile de cache anterior discutate. Cache semiasociativ pe 2 căi Figura 2.2. Cache semiasociativ pe 2 căi Cache complet associativ

27 Arhitectura sistemului ierarhizat de memorie 31 Figura 2.3. Cache complet associativ Cache direct mapat Figura 2.4. Cache direct mapat S-a considerat un bloc compus din 4 cuvinte. Bitul V este un bit de validare a blocului, V = 1 fiind o condiţie necesară a obţinerii hitului. Bitul este util îndeosebi în Sistemele multiprocesor în vederea menţinerii coerenţei memoriilor cache locale datorită redundanţei informaţionale. Mai precis, aici apare necesitatea citirii din cache-ul propriu a ultimei copii modificate a datei respective. Când un procesor modifică o copie locală a

28 Arhitectura sistemului ierarhizat de memorie 32 unei date, toate blocurile care conţin acea dată din cadrul celorlalte procesoare, trebuie invalidate prin resetarea V = 0. Necesitatea invalidării blocurilor (V = 0) apare chiar şi în sistemele uniprocesor. Imediat după resetarea sistemului, uzual, procesorul execută un program încărcător rezident în memoria EPROM. Cum imediat după iniţializarea sistemului conţinutul cache-ului e practic aleator, pentru a evita false hituri la citirea programului încărcător din EPROM, se iniţializează biţii V cu zero. La prima încărcare a unei date (instrucţiuni) în cache, bitul V aferent se va seta pe 1, validând astfel hitul. Bitul D (Dirty) este pus pe 0 la încărcarea iniţială a blocului în cache. La prima scriere a acelui bloc, bitul se pune deci pe 1. Evacuarea propriu-zisă a blocului se face doar dacă bitul D = 1. Practic prin acest bit se minimizează evacuările de blocuri în MP, pe baza principiului că un bloc trebuie evacuat numai dacă a fost scris în cache. În acest sens, din punct de vedere al acceselor de scriere a unui procesor, există 2 posibilităţi: Strategia Write Through (WT), prin care informaţia este scrisă de către procesor atât în blocul aferent din cache cât şi în blocul corespunzător din memoria principală. Mai uşor de implementat decât strategia WB (v. mai jos), nu mai e necesară evacuarea blocului din cache în MP. Scrierea se face la viteza redusă a MP, îngreunată şi de accesarea busului sistem. Pentru a reduce acest dezavantaj deseori se foloseşte un aşa numit Data Write Buffer (DWB). DWB reprezintă o coadă FIFO de lungime parametrizabilă, a cărei valoare trebuie să fie minim IRmax. Fiecare locaţie conţine adresa de memorie (virtuală) şi data de scris. Cu DWB sunt posibile deci STORE-uri simultane, fără el acestea trebuind serializate cu penalităţile de rigoare. În plus DWB va putea rezolva prin "bypassing" foarte elegant hazarduri de tip "LOAD after STORE" cu adrese identice, nemaifiind deci necesară accesarea sistemului de memorie de către instrucţiunea LOAD. Strategia Write - Back (WB), prin care informaţia este scrisă numai în cache, blocul modificat fiind transferat în MP numai la evacuarea din cache. Asigura coerenţă mai facilă (v. în continuare), sincronizare la scriere cu cache-ul, consum redus de putere (nu accesează busul sistem) etc. În vederea menţinerii coerenţei cache-urilor cu precădere în sistemele multimicroprocesor există 2 posibilităţi în funcţie de ce se întâmplă la o scriere (vezi pentru detalii capitolul dedicat sistemelor multimicroprocesor):

29 Arhitectura sistemului ierarhizat de memorie 33 a) Write invalidate prin care CPU care scrie determină ca toate copiile din celelalte memorii cache să fie invalidate înainte ca el săşi modifice blocul din cache-ul propriu. b) Write Broadcast CPU care scrie pune data de scris pe busul comun spre a fi actualizate toate copiile din celelalte cache-uri. Ambele strategii de menţinere a coerenţei pot fi asociate cu oricare dintre protocoalele de scriere (WT, WB) dar de cele mai multe ori se preferă WB cu invalidare. Nu detaliem aici problemele de coerenţă întrucât acestea se referă cu deosebire la problematica sistemelor multiprocesor şi deci depăşesc cadrul acestei prezentări. Se va considera un exemplu care arată cum 2 procesoare pot "vedea" 2 valori diferite pentru aceeaşi locaţie (X) de memorie globală, adică un caz tipic de incoerenţă a unei valori globale. Pas Eveniment Conţinut cache Conţinut cache Conţinut Memorie CPU1 CPU2 globală (X) CPU1 citeşte X CPU2 citeşte X CPU1 scrie 0 în X (WT) WB Tabelul 8.1. Exemplificarea unei incoerenţe S-a presupus că iniţial, nici una din cele 2 cache-uri nu conţine variabila globală X şi că aceasta are valoare 1 în memoria globală. De asemenea s-au presupus cache-uri de tip WT (un cache WB ar introduce o incoerenţă asemănătoare). În pasul 3 CPU 2 are o valoare incoerentă a variabilei X. În continuare, se prezintă un exemplu de protocol de coerenţă WI, bazat pe un protocol de scriere în cache de tip WB. Pas Activitate procesor Activitate pe bus comun Loc.X cache CPU1 Loc.X cache CPU2 Loc. X Memorie globală 0 0

30 Arhitectura sistemului ierarhizat de memorie 34 1 CPU1 citeşte X Cache Miss (X) CPU2 citeşte X Cache Miss (X) CPU1 scrie 1 în X Invalidare X 1 INV. 0 4 CPU2 citeşte X Cache Miss (X) Tabelul 8.2. Coerenţa prin protocol WI În pasul 4, CPU1 abortează ciclul de citire al lui CPU2 din memoria globală şi pune pe busul comun valoarea lui X ("1", copie exclusivă). Apoi, scrie (actualizează) valoarea lui X în cache-ul lui CPU2 şi în memoria globală iar X devine o variabilă partajată. Apar posibile 4 procese distincte într-un cache ca în tabelul următor: Tip Hit / Acţiune în cache acces Miss Citire Miss Evacuare bloc + încărcare bloc nou (alocare cache) Citire Hit (comparare tag-uri) Scriere Miss (Evacuare bloc Dirty=1) + încărcare bloc nou + scriere data în bloc (WB) Scriere Hit Scriere data în blocul din cache (WB) Tabelul 2.1. Tipuri de acces în cache Aşadar, memoriile cache îmbunătăţesc performanţa îndeosebi pe citirile cu hit iar în cazul utilizării scrierii tip Write Back şi pe scrierile cu hit. Îmbunătăţirea accesului la memorie pe citirile CPU este normală având în vedere că acestea sunt mult mai frecvente decât scrierile (orice instrucţiune implică cel puţin o citire din memorie pentru aducerea sa; statistic, cca. 75 % din accesele la memorie sunt citiri). Explicaţia la cauzele miss-urilor în cache-uri, conform literaturii acestui domeniu, sunt de 3 tipuri: datorită faptului că în fond primul acces la un bloc generează întotdeauna miss (compulsory); sunt inevitabile. datorită capacităţii fatalmente limitate a cache-ului care nu poate conţine la un moment dat toate blocurile din MP, ceea ce implică evacuări / încărcări (capacity).

31 Arhitectura sistemului ierarhizat de memorie 35 datorită interferenţelor (conflictelor) unor blocuri din MP pe acelaşi bloc din cache (conflict); acestea se reduc odată cu creşterea capacităţii şi a gradului de asociativitate. Reducerea penalizărilor la un miss în cache se face prin: Niveluri multiple de cache-uri (multi-level inclusion, exclusion, hibrid) L1 Read_Miss aduce bloc din L2 in L1si bloc L1 evacueaza in MP (Multilevel Inclusion) SAU Swap_L2&L1 (Multilevel Exclusion) L1 Write_Hit Write_Back(Multilevel Exclusion); Write_Through (Multilevel Inclusion) L1 Write_Miss (Multilevel Exclusion) aduce bloc din L2/MP si scrie in L1 (WB); (Multilevel Inclusion) aduce bloc L2/MPL1 si scrie in ambele (WT). Aşadar: Multilevel Inclusion L2 mare (redundanta info) Multilevel Exclusion L2 mai mic Memorii victim cache (v. în continuare) Reducerea ratei de miss în cache se face prin: 1. Creşterea mărimii blocului (din păcate cresc şi penalităţile de miss la evacuare-încărcare bloc) 2. Creşterea capacităţii cache (mărire timp acces hit şi costuri) 3. Creştere asociativitate cache (creşte timp acces la hit) 4. Optimizarea de programe prin compilator - intrarea într-un basic-block să reprezinte începutul unui bloc în cache - exploatarea localităţilor spaţiale ale datelor din cache loop interchange etc. Exemplu: for (j=0; j<1000; i++) for (i=0; i<2000; j++) A[i,j]=4*A[i,j]; Dezavantaj: pas (a[i,j]; a[i+1, j]) este 1000 sunt in blocuri diferite in cache scade Rhit

32 Arhitectura sistemului ierarhizat de memorie 36 for (i=0; i<2000; i++) for (j=0; j<1000; j++) A[i,j]=4*A[i,j]; Avantaj: pas (a[i,j] si a[i, j+1]) este 1 sunt in acelasi bloc in cache creste Rhit Primul care a pus în lumină conceptul de memorie cache a fost prof. Maurice Wilkes (Univ. Cambridge, Anglia) un pionier al calculatoarelor care a inventat în 1951 şi tehnica microprogramării unităţilor de comandă aferente procesoarelor într-un articol publicat în 1965 ( Slave memories and dynamic storage allocation, IEEE Trans. Electronic Computers, April, 1965). Prima implementare a unui cache (cu mapare directă) aparţine probabil lui Scarrott, în cadrul unui sistem experimental construit tot la Universitatea din Cambridge. Primul sistem comercial care utiliza cacheurile a fost IBM 360/85 (1968). Conceptul de cache s-a dovedit a fi foarte fecund nu numai în hardware dar şi în software prin aplicaţii dintre cele mai diverse în sistemele de operare (memoria virtuală), reţele de calculatoare, baze de date, compilatoare etc. Pentru a reduce rata de miss a cache-urilor mapate direct (fără să se afecteze însă timpul de hit sau penalitatea în caz de miss), cercetătorul Norman Jouppi (DEC) a propus conceptul de victim cache. Aceasta reprezintă o memorie mică complet asociativă, plasată între primul nivel de cache mapat direct şi memoria principală. Blocurile înlocuite din cache-ul principal datorită unui miss sunt temporar memorate în victim cache. Dacă sunt referite din nou înainte de a fi înlocuite din victim cache, ele pot fi extrase direct din victim cache cu o penalitate mai mică decât cea a memoriei principale. Deoarece victim cache-ul este complet asociativ, multe blocuri care ar genera conflict în cache-ul principal mapat direct, ar putea rezida în victim cache fără să dea naştere la conflicte. Decizia de a plasa un bloc în cache-ul principal sau în victim cache (în caz de miss) este făcută cu ajutorul unei informaţii de stare asociate blocurilor din cache. Biţii de stare conţin informaţii despre istoria blocului. Această idee a fost propusă de McFarling, care foloseşte informaţia de stare pentru a exclude blocurile sigure din cache-ul mapat direct, reducând înlocuirile ciclice implicate de acelaşi bloc. Această schemă, numită excludere dinamică, reduce miss-urile de conflict în multe cazuri. O predicţie greşită implică un acces în nivelul următor al ierarhiei de memorie contrabalansând eventuale câştiguri în performanţă. Schema este mai puţin eficace cu blocuri mari, de capacităţi tipice cache-urilor microprocesoarelor curente.

33 Arhitectura sistemului ierarhizat de memorie 37 Pentru a reduce numărul de interschimbări dintre cache-ul principal şi victim cache, Stiliadis şi Varma au introdus un nou concept numit selective victim cache(svc). Figura 2.5. Ierarhia de memorie pentru scema cu Selective Victim Cache Cu SVC, blocurile aduse din memoria principală sunt plasate selectiv fie în cache-ul principal cu mapare directă fie în selective victim cache, folosind un algoritm de predicţie euristic bazat pe istoria folosirii sale. Blocurile care sunt mai puţin probabil să fie accesate în viitor sunt plasate în SVC şi nu în cache-ul principal. Predicţia este de asemenea folosită în cazul unui miss în cache-ul principal pentru a determina dacă este necesară o schimbare a blocurilor conflictuale. Algoritmul obiectiv este de a plasa blocurile, care sunt mai probabil a fi referite din nou, în cache-ul principal şi altele în victim cache. La referirea unui cache mapat direct, victim cache-ul este adresat în paralel; dacă rezultă miss în cache-ul principal, dar hit în victim cache, instrucţiunea (în cazul ICache-ului) este extrasă din victim cache. Penalitatea pentru miss în cache-ul principal, în acest caz este mult mai redusă decât costul unui acces în nivelul următor de memorie. Algoritmul de victim cache încearcă să izoleze blocurile conflictuale şi să le memoreze doar unul în cache-ul principal restul în victim cache. Dacă numărul blocurilor conflictuale este suficient de mic să se potrivească în victim cache, atât rata de miss în nivelul următor de memorie cât şi timpul mediu de acces va fi îmbunătăţit datorită penalităţii reduse implicate de prezenţa blocurilor în victim cache.

34 Arhitectura sistemului ierarhizat de memorie 38 Cache-ul mapat direct creşte cu un bloc pentru a implementa conceptul de selective victim cache. Acest bloc adiţional se numeşte bloc tranzitoriu, şi este necesar pentru două motive. Primul ar fi acela că, blocul tranzitoriu este folosit de algoritmul de predicţie pentru referiri secvenţiale într-un acelaşi bloc. Hardware-ul este capabil să determine accese secvenţiale, folosind semnalul Acces Secvenţial activat de CPU, când referirea curentă se face în acelaşi bloc ca şi cel anterior. Semnalul este folosit de către cache pentru a evita actualizarea biţilor de stare folosiţi de algoritmul de predicţie la referinţe repetate în acelaşi bloc tranzitoriu. Al doilea motiv constă în faptul că, atunci când are loc un hit în victim cache şi algoritmul de predicţie decide să nu se interschimbe blocurile, blocul corespondent este copiat din victim cache în blocul tranzitoriu. Astfel, blocul tranzitoriu serveşte ca buffer, accesele secvenţiale la acel bloc fiind satisfăcute direct din acest buffer la timpul de acces al cache-ului principal. Similar, la un miss în următorul nivel de memorie, algoritmul de predicţie va decide să plaseze blocul sosit în victim cache şi în blocul tranzitoriu. Întrucât un al doilea sau un al n-lea acces consecutiv în acelaşi bloc în cache-ul principal poate fi servit din blocul tranzitoriu, acestuia îi este adăugat un bit de stare pentru a adresa cache-ul principal. Acest bit de stare urmăreşte starea datei din blocul tranzitoriu. Când starea este normală, adresa sosită pe bus este decodificată pentru a accesa cache-ul principal în mod obişnuit; când starea este specială, accesul se face în blocul tranzitoriu. Figura următoare arată tranziţiile dintre cele două stări. Mai jos se prezintă acest algoritm sub formă de maşină secvenţială de stare. Figura 2.6. Maşina secvenţială de stare SVC şi tranziţiile ei Iniţial starea maşinii este resetată în stare normală. Dacă avem un miss în cache-ul mapat direct, acesta este servit fie de victim cache fie de nivelul următor de memorie. În fiecare din cazuri, algoritmul de predicţie este folosit pentru a determina care bloc urmează a fi memorat în cache-ul

35 Arhitectura sistemului ierarhizat de memorie 39 principal. Dacă algoritmul de predicţie plasează blocul accesat în cache-ul principal, starea maşinii rămâne în stare normală. Altfel, blocul este copiat în blocul tranzitoriu di acest cache şi maşina tranzitează în starea specială. Referirea secvenţială a aceluiaşi bloc păstrează semnalul Acces Secvenţial activat iar maşina în starea specială. Datele se extrag din blocul tranzitoriu. Primul acces nesecvenţial resetează starea maşinii în stare normală, distingându-se trei cazuri distincte, pe care le vom discuta mai jos. Algoritmul Selective Victim Cache 1. Hit în cache-ul principal: dacă cuvântul este găsit în cache-ul principal, el este extras pentru CPU. Nu este nici o diferenţă faţă de cazul cacheului mapat direct. Singura operaţie suplimentară este o posibilă actualizare a biţilor de stare folosiţi de schema de predicţie. Actualizarea se poate face în paralel cu operaţia de fetch şi nu introduce întârzieri suplimentare. 2. Miss în cache-ul principal, hit în victim cache: în acest caz, cuvântul este extras din victim cache în cache-ul mapat direct şi înaintat CPU. Un algoritm de predicţie este invocat pentru a determina dacă va avea loc o interschimbare între blocul referit şi blocul conflictual din cache-ul principal. Dacă algoritmul decide că blocul din victim cache este mai probabil să fie referit din nou decât blocul conflictual din cache-ul principal se realizează interschimbarea; altfel blocul din victim cache este copiat în blocul tranzitoriu al cache-ului principal iar maşină secvenţială de stare trece în starea specială. Data poate fi înaintată CPU. În ambele cazuri blocul din victim cache este marcat drept cel mai recent folosit din lista LRU. În plus, biţii de predicţie sunt actualizaţi pentru a reflecta istoria acceselor. 3. Miss atât în cache-ul principal cât şi în victim cache: dacă cuvântul nu este găsit nici în cache-ul principal nici în victim cache, el trebuie extras din nivelul următor al ierarhiei de memorie. Aceasta înseamnă că fie blocul corespondent din cache-ul principal este gol, fie noul bloc este în conflict cu un alt bloc memorat în cache (mai probabil). În primul caz, noul bloc este adus în cache-ul principal iar victim cache-ul nu este afectat. În cel de-al doilea caz, trebuie aplicat algoritmul de predicţie pentru a determina care din blocuri este mai probabil să fie referit pe viitor. Dacă blocul care soseşte din memoria centrală are o probabilitate mai mare decât blocul conflictual din cache-ul principal, ultimul este mutat în victim cache şi noul bloc îi ia locul în cache; altfel, blocul sosit este direcţionat spre victim cache şi copiat în blocul tranzitoriu al cacheului mapat direct, de unde poate fi accesat mai iute de către CPU.

36 Arhitectura sistemului ierarhizat de memorie 40 Maşină secvenţială de stare trece în starea specială iar biţii de predicţie sunt actualizaţi. Diferenţa de esenţă dintre schema prezentată (selective victim cache) şi conceptul de victim cache simplu se observă în cazurile 2 şi 3. În cazul 2, blocurile conflictuale din cache-ul principal şi cele din victim cache sunt întotdeauna schimbate în cazul folosirii victim cache-ului tradiţional, pe când schema prezentată face acest lucru într-un mod selectiv, euristic. Similar, în cazul 3, prin folosirea victim cache-ului obişnuit blocurile din memorie sunt întotdeauna plasate în cache-ul principal, pe cînd în cazul Selective Victim Cache-ului plasează aceste blocuri selectiv în cache-ul principal sau în victim cache. Orice algoritm de înlocuire poate fi folosit pentru victim cache. LRU (cel mai puţin recent referit) pare să fie cea mai bună alegere, întrucât scopul victim cache-ului este de a captura cele mai multe victime recent înlocuite şi victim cache-ul este de dimensiune mică. Algoritmul de Predicţie Scopul algoritmului de predicţie este de determina care din cele două blocuri conflictuale este mai probabil să fie referit pe viitor. Blocul considerat cu o probabilitate mai mare de acces în viitor este plasat în cacheul principal, celălalt fiind plasat în victim cache. Astfel, dacă blocul din victim cache este pe viitor înlocuit datorită capacităţii reduse a victim cacheului, impactul ar fi mai puţin sever decât alegerea opusă (interschimbarea permanentă a blocurilor din cazul schemei cu victim cache obişnuit). Algoritmul de predicţie se bazează pe algoritmul de excludere dinamică propus de McFarling. Algoritmul foloseşte doi biţi de stare asociaţi fiecărui bloc, numiţi hit bit şi sticky bit. Hit bit este asociat logic cu blocul din nivelul 1 (L1 - level one) al cache-ului care se află pe nivelul 2 (L2) sau în memoria centrală. Hit bit egal cu 1 logic indică, faptul că a avut cel puţin un acces cu hit la blocul respectiv de cînd el a părăsit cache-ul principal (cache-ul de pe nivelul L1). Hit bit egal cu 0 înseamnă că blocul corespunzător nu a fost deloc accesat de când a fost înlocuit din cache-ul principal. Într-o implementare ideală, biţii de hit sunt menţinuţi în nivelul L2 de cache sau în memoria principală şi aduşi în nivelul L1 de cache cu blocul corespondent. Dacă blocul este înlocuit din cache-ul principal (L1 cache), starea bitului de hit trebuie actualizată în L2 cache sau în memoria centrală. Când un bloc, să-l numim α, a fost adus în cache-ul principal, bitul său sticky este setat. Fiecare secvenţă cu hit la blocul α reîmprospătează bitul sticky la valoarea 1. La referirea unui bloc conflictual, fie acesta β, dacă algoritmul de predicţie decide ca blocul să nu fie înlocuit din cache-ul principal atunci bitul sticky este resetat. Dacă un acces ulterior în cache-ul

37 Arhitectura sistemului ierarhizat de memorie 41 principal intră în conflict cu blocul care are bitul sticky resetat, atunci blocul va fi înlocuit din cache-ul principal. De aceea, sticky bit de valoare 1 pentru blocul α semnifică faptul că nu a avut loc nici o referire la un bloc conflictual cu α, de la ultima referire a acestuia. Este uşor de înţeles rolul blocului tranzitoriu în algoritmul de predicţie. Dacă algoritmul tratează toate fetch-urile în acelaşi fel, accesele secvenţiale în acelaşi bloc vor seta întotdeauna bitul sticky. Algoritmul de predicţie va fi incapabil să determine dacă blocul a fost referit repetat în interiorul unei bucle, sau dacă mai mult decât un cuvânt din acelaşi bloc a fost extras din cache fără o referinţă intervenită la un alt bloc. Figura 2.7. Algoritmul de Selective Victim Cache În algoritmul Selective Victim Cache prezentat în figura anterioară, se disting trei cazuri: în primul caz, un hit în cache-ul principal setează biţii de stare hit şi sticky. În al doilea caz, blocul accesat, fie acesta β, se consideră rezident în victim cache. Acesta implică un conflict între blocul β şi cel din cache-ul principal, notat α. În acest caz, algoritmul de predicţie este aplicat pentru a determina dacă va avea loc o interschimbare. Dacă bitul sticky al lui α este 0, semnificând faptul că blocul nu a fost accesat de la conflictul

38 Arhitectura sistemului ierarhizat de memorie 42 anterior la acest bloc, noul bloc β primeşte o prioritate superioară lui α, determinând o interschimbare. De asemenea, dacă bitul hit al lui β este setat pe 1, acestuia îi este dată o prioritate mai mare decât lui α, şi ele sunt interschimbate. Dacă bitul sticky al lui α este 1 şi bitul hit al lui β este 0, accesul este satisfăcut din victim cache şi nu are loc nici o interschimbare (se consideră că blocul β nu este suficient de valoros pt. a fi adus în cache-ul principal). Bitul sticky aferent lui α este resetat astfel încât o secvenţă următoare care implică conflict la acest bloc va determina mutarea lui α din cache-ul principal. În final, cazul 3 al algoritmului prezintă secvenţa de acţiuni care au loc în cazul unor accese cu miss atât în cache-ul principal cât şi în victim cache. Secvenţa este similară cu cea de la cazul 2, cu excepţia faptului că, destinaţia blocului sosit se alege fie cache-ul principal fie victim cache-ul. În situaţia cu victim cache simplu, blocul conflictual din cache-ul principal era mutat în victim cache înainte să fie înlocuit. În cazul de faţă când blocul sosit este plasat în victim cache, el este de asemenea plasat şi în blocul tranzitoriu pentru a servi eventualele viitoare referinţe secvenţiale. Operaţiile algoritmului de Selective Victim Cache pot fi ilustrate printr-o secvenţă de instrucţiuni repetate (α m βγ) n implicând trei blocuri conflictuale α, β şi γ. Notaţia (α m βγ) n reprezintă execuţia unei secvenţe compusă din două bucle de program imbricate, bucla interioară constând în m referinţe la blocul α, urmate de accesul la blocurile β şi γ în bucla exterioară, care se execută de n ori. Primul acces îl aduce pe α în cache-ul principal şi atât bitul hit cât şi cel sticky sunt setaţi după cel mult două referiri ale acestuia. Când β este referit, bitul său hit este iniţial 0. De aceea el nu-l înlocuieşte pe α în cache-ul principal şi este memorat în victim cache. Conflictul generat determină resetarea bitului sticky al lui α. Când γ este referit, bitul său hit este 0, dar bitul sticky al lui α este tot 0. Deci, γ îl înlocuieşte pe α. Blocul α este transferat în victim cache şi bitul său hit rămâne 1 datorită referinţei sale anterioare. În ciclul următor când α este referit din nou, el este mutat înapoi în cache-ul principal datorită bitului său de hit, rămas setat. Astfel, dacă victim cache-ul este suficient de mare pentru a încape atât α şi β, sau β şi γ, doar trei referinţe ar fi servite de către al doilea nivel de cache. Numărul total de interschimbări nu va depăşi 2n. În cazul unei scheme simple de predicţie fără victim cache, numărul total de referiri cu miss ar fi 2n, în cazul în care schema poate rezolva doar conflicte între două blocuri. Un victim cache simplu, fără predicţie ar fi capabil să reducă numărul de accese cu miss la cel de-al doilea nivel de cache la 3, dar ar necesita 3n interschimbări în timpul execuţiei buclei exterioare, cu

39 Arhitectura sistemului ierarhizat de memorie 43 influenţe evident defavorabile asupra timpului global de procesare. Aceasta arată avantajul Selective Victim Cache-ului superioară altor scheme care tratează conflicte implicând mai mult de două blocuri. De reţinut că, penalitatea pentru o predicţie greşită în această schemă este limitată la accesul în victim cache şi o posibilă interschimbare, presupunând că victim cache-ul este suficient de mare pentru a reţine blocurile conflictuale între accese. Metrici de performanţă Metricile de performanţă folosite sunt rata de miss la nivelul L1 de cache şi timpul mediu de acces la ierarhia de memorie. În cazurile cu victim cache simplu şi cel cu victim cache selectiv, folosim de asemenea şi numărul de interschimbări între cache-ul principal şi victim cache ca metrică de comparaţie. Rata de miss la nivelul L1 de cache se bazează pe numărul de referinţe propagate în nivelul următor al ierarhiei de memorie. În caz de miss în cache-ul principal acestea sunt servite de către victim cache, fiind plătită o penalitate pentru accesul în victim cache precum şi pentru interschimbările de blocuri rezultate între cache-ul principal şi victim cache. Timpul mediu de acces la ierarhia de memorie ia în calcul şi aceste penalizări şi de aceea este un bun indicator al performanţei memoriei sistemului, desigur mai complet decât rata de miss în nivelul L1 de cache. Deoarece obiectivul principal al victim cache-ului este de a reduce numărul de miss-uri de conflict în cache-ul mapat direct, este de asemenea important să comparăm procentul de miss-uri de conflict eliminate prin fiecare din scheme. Miss-urile de conflict sunt de obicei calculate ca missuri suplimentare ale unui cache, comparate cu un cache complet asociativ de aceeaşi mărime şi care dezvoltă un acelaşi algoritm de înlocuire. Algoritmul folosit este LRU (Least Recently Used, cel mai de demult nefolosit) sau variaţiuni. Modelarea timpului de acces la ierarhia de memorie Estimarea timpului de acces se face ca o funcţie de mărimea cacheului, dimensiunea blocului, asociativitatea şi organizarea fizică a cache-ului. Presupunem că penalitatea medie pentru un miss în cache-ul de pe nivelul L1 este acelaşi pentru toate arhitecturile şi este de p ori ciclul de bază al cache-lui principal, unde p variază între 1 şi 100. Considerăm un bloc de dimensiune de 32 octeţi, penalitate în caz de miss de de cicli, în caz că nu există un nivel L2 de cache. Câteva studii, raportează că penalitatea pentru un miss poate fi până la de cicli când nu este inclus un al doilea nivel de cache. Parametrii Cache Victim Selective 2-way

40 Arhitectura sistemului ierarhizat de memorie 44 Mapat Direct Cache Simplu Victim Cache cache Referinţe totale R Număr total de miss-uri în L1 M d M v M s M 2 cache Hit-uri în victim cache h v h s Interschimbări între victim cache I v I s şi cache-ul principal Timp mediu de acces T d T v T s T 2 Timp mediu de penalizare (în cicli p CPU) Perioada de tact CPU clk clk 2-way Tabelul 2.2. Notaţiile folosite în calculul timpului de acces Tabelul 2.2., rezumă toate notaţiile privitoare la calculul timpului de acces la memorie. R este numărul total de referinţe generate de programele de tip trace. În cazul cache-ului simplu mapat direct, M d reprezintă numărul total de accese cu miss în cache. În cazul folosirii unui victim cache obişnuit sau a unui Selective Victim Cache, M v şi M s sunt folosite pentru a nota numărul de accese cu miss în primul nivel de cache care sunt servite de al doilea nivel al ierarhiei de memorie. Numărul total de hituri în victim cache pentru aceste scheme le-am notat cu h v şi respectiv h s. Timpul mediu de acces pentru un cache mapat direct se calculează astfel: R + p M d M d Td = clk = clk 1+ p (2.1) R R Pentru fiecare miss, sunt necesari p cicli suplimentari. Presupunem că cei p cicli includ toate cheltuielile CPU-ului. În cazul victim cache-ului simplu, o penalitate de p cicli este produsă la fiecare miss în primul nivel al ierarhiei de memorie. În plus, pentru fiecare referinţă servită de către victim cache, o penalizare suplimentară de cel puţin un ciclu este plătită pentru accesarea în victim cache, iar operaţia de interschimbare dintre cache-ul principal şi victim cache necesită o penalitate de câţiva cicli (presupunem 3 cicli, de altfel minimali). Această penalitate ar fi chiar mai mare dacă matricea memoriei cache-ului mapat direct sau a victim cache-ului este organizată fizic în cuvinte egale cu o fracţiune din mărimea blocului de cache. De exemplu, blocul poate avea dimensiunea de 32 de octeţi, dar

41 Arhitectura sistemului ierarhizat de memorie 45 cache-ul poate fi organizat în cuvinte de 8 sau 16 octeţi. În acest caz penalitatea pentru interschimbare va fi multiplicată cu raportul: Dimensiunea blocului de cache Mãrimea cuvântului de date al cache - ului Astfel, timpul mediu de acces la memorie pentru un sistem cu victim cache simplu, se calculează astfel: M v h v + 3 I v Tv = clk 1 + p + (2.2) R R Într-un sistem cu Selective Victim Cache, timpul mediu de acces la memorie poate fi calculat în acelaşi fel ca în cazul victim cache-ului simplu. O penalitate de p cicli este aplicată de câte ori este accesat nivelul următor al ierarhiei de memorie. Un ciclu suplimentar este necesar la un hit în victim cache şi 3 cicli suplimentari pentru operaţia de interschimbare de blocuri. Timpul mediu de acces la memorie este dat de formula: Ms hs + 3 Is Ts = clk 1 + p + (2.3) R R Se observă că, chiar dacă rata de miss M s este foarte aproape de cea a victim cache-ului simplu, sistemele ce folosesc selective victim cache pot totuşi oferi o îmbunătăţire substanţială a performanţei superioară sistemelor cu victim cache simplu, din următoarele două motive: 1. Rata de miss locală în cache-ul principal poate fi îmbunătăţită printr-un plasament mai bun al blocurilor. 2. Numărul de interschimbări poate descreşte ca rezultat al algoritmului de predicţie. Aceasta reduce media penalizării pentru accesele care sunt servite de victime cache, în special când numărul de cicli folosiţi la o interschimbare este ridicat. Se foloseşte timpul mediu de acces la memorie pentru un sistem cu un cache 2-way associative, ca o referinţă pentru evaluarea performanţei sistemului cu selective victim cache. Pentru estimarea timpului de acces la un cache cache 2-way associative, se presupune că penalitatea în nanosecunde pentru al doilea nivel al ierarhiei de memorie rămâne aceeaşi ca şi în cazul cache-ului mapat direct. Pot exista unele constrângeri de implementare care afectează penalitatea în caz de miss. Accesarea magistralei sistem, poate implica o secvenţă de operaţii care necesită un

42 Arhitectura sistemului ierarhizat de memorie 46 număr fix de perioade de tact. Astfel, numărul de cicli necesari pentru deservirea unui miss nu poate descreşte proporţional cu creşterea perioadei de tact CPU, rezultând într-o penalizare mai mare în cazul cache-ului cache 2-way associative. Timpul mediu de acces la memorie acestui cache este estimat de relaţia: T 2 = clk clk clk + p M R 2-way 2 (2.4) Primul termen reprezintă timpul de acces la cache iar al doilea termen este timpul de acces la nivelul următor de memorie. Comparând această ecuaţie cu (2.1), orice îmbunătăţire a performanţei se datorează celui de-al doilea termen, în timp ce primul termen reprezintă câştigul introdus prin asociativitatea cache-ului asupra timpului de acces. Dacă îmbunătăţirea datorată celui de-al doilea termen nu este adecvată pentru a compensa acest câştig, performanţa cache-ului 2-asociativ poate fi inferioară celei a cacheului mapat direct. Îmbunătăţirea în performanţă obţinută atât prin victim cache cât şi prin selective victim cache variază în funcţie de trace, depinzând de mărimea lor şi de numărul de conflicte de acces pe care schema de predicţie le elimină. Chiar pentru programe mici, selective vitim cache asigură o îmbunătăţire semnificativă comparată cu victim cache-ul simplu, când cache-ul nu este suficient de mare pentru a memora întreg programul. Stiliadis şi Varma, afirmă că cea mai bună îmbunătăţire a performanţei în termenii ratei de miss, de aproximativ 33%, este obţinută pentru cache-uri de instrucţiuni de 8 până la 16 Kocteţi. Pentru cache-uri mai mari de dimensiuni 64 până la 128 Kocteţi, majoritatea trace-urilor pot fi uşor memorate în cache şi missurile de conflict reprezintă un mic procent din numărul total de accese cu miss. În aceste cazuri victim cache-ul simplu este capabil să elimine majoritatea conflictelor, şi performanţa sa este comparabilă cu cea a selective victim cache-ului. O problemă potenţială cu algoritmul de predicţie dezvoltat în selective victim cache este aceea că, performanţa sa se poate degrada odată cu creşterea dimensiunii blocului, ca rezultat al partajării biţilor de stare de cuvinte din interiorul aceluiaşi bloc. Selective victim cache asigură o îmbunătăţire semnificativă a ratei de miss indiferent de dimensiunea blocului. Pentru blocuri de dimensiune de 4 octeţi, selective victim cache reduce rata de miss cu aproximativ 30% faţă de o arhitectură cache cu mapare directă, în timp ce pentru blocuri de dimensiuni de 64 octeţi, rata de miss este redusă cu aproape 50%. Aceste rezultate contrazic

43 Arhitectura sistemului ierarhizat de memorie 47 comportamentul excluziunii dinamice, unde reducerea ratei de miss scade cu creşterea dimensiunii blocului. Rezultatele se datorează menţinerii la aceeaşi dimensiune a victim cache-ului în termenii numărului de blocuri, astfel că, o creştere a dimensiunii blocului determină o creştere efectivă a capacităţii cache-ului. Această creştere în capacitate compensează mai mult decât orice degradare a ratei de predicţi prin creşterea dimensiunii blocului. Acest fapt nu creşte semnificativ complexitatea implementării victim cacheului, deoarece asociativitatea rămâne aceeaşi. Indiferent de mărimea cacheului, numărul de interschimbări prin folosirea selective victim cache-ului este redus cu 50% sau mai mult faţă de folosirea unui victim cache simplu. Când dimensiunea blocului este mai mare, în funcţie de implementare, operaţia de interschimbare poate necesita câţiva cicli. Prin îmbunătăţirea atât a ratei de hit cât şi a numărului de interschimbări, selective victim cache-ul poate creşte semnificativ performanţa primului nivel de cache, superioară victim cache-ului simplu şi cache-ului two-way set associative. Pentru diverse dimensiuni de cache, îmbunătăţirea ratei de miss la cache-ul twoway semiasociativ nu este suficientă pentru a compensa creşterea timpului de acces, rezultând într-o creştere netă a timpului mediu de acces la memorie superior cache-urilor mapate direct. Cea mai mare creştere în performanţă a selective victim cache-ului superioară cache-ului semiasociativ, este aproximativ 25%, obţinută pentru dimensiuni de cacheuri de Kocteţi. Politica de scriere implementată este write back cu write allocate. Pentru a menţine proprietatea de incluziune multinivel, blocurile din cacheul de pe nivelul L1 au fost invalidate când au fost înlocuite pe nivelul L2 de cache. Deşi selective victim cache-ul produce îmbunătăţiri semnificative ale ratei de hit comparativ cu cache-urile mapate direct de dimensiune redusă, performanţa sa este inferioară celei obţinută folosind victim cache simplu. De fapt, îmbunătăţirile ratei de miss variază semnificativ în funcţie de traceuri. Sunt două motive care explică acest raţionament: primul este natura acceselor la memorie a programelor folosite. Programele care implică o alocare statică a datelor şi structurilor de date, arată o îmbunătăţire cu selective victim cache, ca rezultat al folosirii algoritmului de predicţie. Structurile de date principale ale acestor programe sunt vectori. Algoritmul de predicţie este capabil să rezolve un număr mare de conflicte în aceste cazuri, fără să acceseze al doilea nivel. În programele cu alocare dinamică a memoriei şi folosire a extensiei de pointeri, conflictele sunt mai greu de rezolvat de către algoritmul de predicţie. Ratele de miss în situaţia folosirii selective victim cache-ului pentru aceste trace-uri sunt mai mari decât în cazul folosirii unui simplu victim cache. În timp ce pentru selective victim cache presupunem un al doilea nivel de cache şi menţinem proprietatea de

44 Arhitectura sistemului ierarhizat de memorie 48 incluziune, simularea victim cache-ului simplu presupune că al doilea nivel al ierarhiei este memoria principală. Chiar dacă îmbunătăţirile asupra ratei de miss sunt mai puţin convingătoare în cazul cache-urilor de date comparativ cu cel de instrucţiuni, selective victim cache poate reduce timpul mediu de acces la memorie pentru primul nivel al cache-ului de date prin reducerea numărului de interschimbări. Pentru cache-uri de dimensiuni până la 64 Kocteţi, numărul de interschimbări pentru selective victim cache este mult mai mic decât cel pentru victim cache simplu. În câteva cazuri îmbunătăţirea este mai mare de 50%. Numărul de interschimbări pentru victim cache simplu descreşte sub selective victim cache pentru dimensiuni mai mari sau egale cu 128 Kocteţi. Astfel, pentru cache-uri de 128 Kocteţi, selective victim cache este capabil să reducă rata de miss prin creşterea numărului de interschimbări. Deşi, victim cache-ul simplu, pare să se comporte mai bine decât selective victim cache-ul, pentru cache-uri de dimensiuni sub 8 Kocteţi, din punct de vedere al timpului mediu de acces. Performanţa cacheului semiasociativ este inferioară ambelor (simplu victim cache şi selective victim cache), dar superioară cache-ului mapat direct. Trace-urile de date sunt caracterizate de o rată de miss mai mare decât trace-urile de instrucţiuni. În plus miss-urile de conflict sunt răspunzătoare de procentul ridicat din rata totală de miss. Sunt două consecinţe ale acestui fapt: primul, efectul reducerii ratei de miss asupra timpului de acces la memorie este mai pronunţat, iar al doilea, cache-urile semiasociative pe 2 căi asigură îmbunătăţiri în timpul mediu de acces chiar şi pentru cache-uri mari, spre deosebire de cache-urile de instrucţiuni, unde avantajul obţinut prin reducerea ratei de miss datorată creşterii asociativităţii este mai mare decât câştigul obţinut asupra timpului de acces la cache. Concluzionăm că, atât victim cache-ul simplu cât şi selective victim cache-ul sunt mult mai puţin atractive pentru folosire în cache-ul de date comparativ cu cel de instrucţiuni. În continuare se analizează modul în care informaţiile de stare de care are nevoie schema de predicţie dezvoltată în selective victim cache pot fi stocate în interiorul ierarhiei de memorie. După cum s-a arătat schema selective victim cache-ului necesită doi biţi de stare pentru a păstra informaţii despre istoria blocurilor din cache - bitul sticky şi bitul hit. Bitul sticky este asociat logic cu blocul din cache-ul principal. De aceea este normal să se memoreze acest bit în cache-ul mapat direct ca parte a fiecărui bloc. Pe de altă parte, bitul hit este asociat logic cu fiecare bloc din memoria principală. Astfel, într-o implementare perfectă, biţii de hit trebuie memoraţi în memoria principală. Această abordare este impracticabilă în majoritatea cazurilor.

45 Arhitectura sistemului ierarhizat de memorie 49 Figura 2.8. Implementarea schemei de memorare a biţilor de hit Dacă ierarhia de memorie include un la doilea nivel de cache, este posibil să se memoreze biţii de hit în cadrul blocurilor din acest nivel. Când un bloc este adus pe nivelul L1 de cache din nivelul L2, o copie locală a bitului de hit este memorată în blocul de pe nivelul L1. Aceasta elimină nevoia de acces a nivelului L2 de cache de fiecare dată când bitul hit este actualizat de către algoritmul de predicţie. Când blocul este înlocuit din nivelul L1 de cache, bitul hit corespondent este copiat în nivelul L2. O problemă ar fi însă aceea că, multiple locaţii din memoria principală sunt forţate să împartă acelaşi bit de pe nivelul L2. Astfel, când un bloc este înlocuit de pe nivelul L2 de cache, toate informaţiile lui de stare se pierd, reducând eficacitatea algoritmului de predicţie. De fiecare dată când un bloc este adus pe nivelul L2 de cache din memoria principală, bitul hit al său trebuie setat la o valoare iniţială. Pentru o secvenţă specifică de acces, valori iniţiale diferite pot produce rezultate diferite. Cu cache-urile de pe nivelul L2 de dimensiuni mari, efectul valorilor iniţiale este probabil mai mic. O tratare alternativă este de a menţine biţii de hit în interiorul CPU, în cadrul nivelului L1 de cache. În abordarea lui Stiliadis şi Varma, un şir de biţi de hit numit hit array este menţinut ca parte a nivelului L1 de cache. Fiecare bloc de memorie este asociat unuia din biţii acestui şir. Lungimea şirului este inevitabil mai mică decât numărul maxim de blocuri care pot fi adresate. Deci, mai mult de un bloc va fi mapat aceluiaşi bit de hit, cauzând datorită interferenţelor un aleatorism ce trebuie introdus în procesul de predicţie. Deşi, aceasta poate potenţial reduce performanţa selective victim cache-ului, rezultatele simulărilor nu confirmă acest lucru chiar şi pentru şiruri de hit de dimensiune modestă.

46 Arhitectura sistemului ierarhizat de memorie 50 Implementarea nivelului L1 de cache sistem este prezentată în Figura 4. Bitul sticky este menţinut cu fiecare bloc în cache-ul principal. Nici un bit de stare nu este necesar în victim cache. Biţii de hit sunt păstraţi în hit array, adresaţi de o parte a adresei de memorie. Dimensiunea şirului de hit bit este aleasă ca un multiplu al numărului de blocuri din cache-ul principal. Astfel, Dimensiunea şirului hit array = Număr de blocuri în cache-ul principal H unde H determină gradul de partajare a biţilor de hit de către blocurile memoriei principale. Se presupune că H este o putere a lui 2, H=2 h. Hit array poate fi adresat de adresa de bloc concatenată cu cei mai puţin semnificativi biţi h, din partea de tag a adresei. O valoare mare pentru H implică mai puţine interferenţe între blocurile conflictuale la biţii de hit. Dacă H este ales ca raport dintre dimensiunea cache-ului de pe nivelul L2 şi cea a cache-ului de pe nivelul L1 (principal), atunci efectul este similar cu menţinerea biţilor hit în nivelul L2 de cache. O problemă a implementării schemei atât a victim cache-ului cât şi a selective victim cache-ului este costul implementării victim cache-ului full asociativ. Chiar şi atunci când aceste cache-uri sunt foarte mici, costul hardware al memoriei adresabilă contextual (CAM) poate fi semnificativ. Cache-urile complet asociative cu algoritm de înlocuire LRU pot uneori suferi de o rată de miss mai ridicată decât cache-urile two-way asociative deoarece algoritmul de înlocuire nu este cel optimal. Efectul ambelor probleme de mai sus poate fi diminuat prin reducerea asociativităţii victim cache-ului. Cu un victim cache semiasociativ pe 2 căi, nu se observă nici o creştere a ratei de miss la nivelul următor al ierarhiei de memorie pentru nici o instrucţiune din trace-urile simulate, atât în victim cache simplu cât şi în selective victim cache. Surprinzător, victim cache-ul semiasociativ pe 2 căi poate îmbunătăţi rata de miss şi timpul mediu de acces pentru mai multe trace-uri. Acest comportament se datorează algoritmului de înlocuire LRU dezvoltat în victim cache-ul complet asociativ. Blocurile mutate în victim cache-ul complet asociativ ca rezultat al conflictelor din cache-ul principal sunt înlocuite frecvent înainte de a fi accesate din nou. Victim cache-ul semiasociativ pe 2 căi asigură o mai bună izolare pentru blocurile sale în multe cazuri, micşorând rata de miss în victim cache. În plus, datorită dimensiunii sale reduse, miss-urile de conflict formează doar o mică fracţiune din numărul total de accese cu miss în victim cache comparativ cu miss-urile de capacitate. Aceasta limitează îmbunătăţirea ratei de miss prin creşterea asociativităţii victim cache-ului, chiar cu un algoritm optimal de înlocuire. Se observă că, victim cache-ul full asociativ poate îmbunătăţi

47 Arhitectura sistemului ierarhizat de memorie 51 dramatic rata de miss în cazul conflictelor ce implică mai mult de trei blocuri, blocurile conflictuale fiind reţinute în victim cache între accese. Cu un victim cache simplu conţinutul cache-ului principal mapat direct este neafectat de asociativitatea acestuia. Astfel, rata de miss locală rămâne neschimbată în timp ce se variază asociativitatea victim cache-ului. Prin urmare toate îmbunătăţirile efectuate asupra ratei de miss la nivelul L1 de cache pot fi atribuite îmbunătăţirii ratei de miss locale a victim cacheului. Cu victim cache-ul selectiv, asociativitatea poate afecta potenţial atât rata de miss locală a cache-ului principal cât şi numărul de interschimbări dintre cele două cache-uri. Comparaţia timpului de acces ţine cont de schimbările apărute în rata de miss şi numărul de interschimbări (substanţial micşorat) şi de aceea timpul mediu de acces reprezintă o măsură mai bună pentru caracterizarea efectului de asociativitate al victim cache-ului asupra performanţei sistemului. Chiar cu un victim cache mapat direct, timpul mediu de acces este mai mare sau egal decât cel din cazul victim cache-ului complet asociativ. Când folosim un victim cache de date semiasociativ pe 2 căi, rezultatele sunt mai proaste decât acelea cu un victim cache complet asociativ, atât pentru victim cache simplu cât şi pentru victim cache-ul selectiv. Acest lucru nu surprinde, dând conflictelor de acces la date o natură aleatorie. Astfel, un cache complet asociativ poate fi încă atractiv când este folosit ca şi cache de date. Totuşi, îmbunătăţirile observate sunt mai mici. Chiar dacă nu este nici o îmbunătăţire a ratei de hit în cache-ul principal, schema victim cache-ului selectiv poate totuşi asigura o îmbunătăţire a performanţei superioară victim cache-ului simplu. Pentru schema cu SVC rezultatele demonstrează că îmbunătăţirile de performanţă sunt puternic determinate de impactul algoritmului de predicţie asupra numărului de interschimbări cu cache-ul mapat direct. Algoritmul poate de asemenea contribui la o mai bună plasare a blocurilor în cache, reducând numărul de accese în victim cache şi generând rate de hit ridicate în cacheul mapat direct. Folosirea victim cache-ului selectiv determină îmbunătăţiri ale ratei de miss precum şi ale timpului mediu de acces la memorie, atât pentru cacheuri mici cât şi pentru cele mari (4Kocteţi Kocteţi). Simulări făcute pe trace-uri de instrucţiuni a 10 benchmark-uri SPEC 92 arată o îmbunătăţire de aproximativ 21% a ratei de miss, superioară folosirii unui victim cache simplu de 16 Kocteţi cu blocuri de dimensiuni de 32 octeţi; numărul blocurilor interschimbate între cache-ul principal şi victim cache s-a redus cu aproximativ 70%.

48 Arhitectura sistemului ierarhizat de memorie MEMORIA VIRTUALĂ Memoria virtuală reprezintă o tehnică de organizare a memoriei prin intermediul căreia programatorul vede un spaţiu virtual de adresare foarte mare şi care, fără ca programatorul să simtă, este mapat în memoria fizic disponibilă. Uzual, spaţiul virtual de adrese corespunde suportului disc magnetic, programatorul având iluzia prin mecanismele de memorie virtuală (MV), că deţine o memorie (virtuală) de capacitatea hard-discului şi nu de capacitatea memoriei fizice preponderentă DRAM (limitată la Mo la ora actuală). În cazul MV, memoria principală este analoagă memoriei cache între CPU (Central Processing Unit) şi memoria principală, numai că de această dată ea se situează între CPU şi discul hard. Deci memoria principală (MP) se comportă oarecum ca un cache între CPU şi discul hard. Prin mecanismele de MV se măreşte probabilitatea ca informaţia ce se doreşte a fi accesată de către CPU din spaţiul virtual (disc), să se afle în MP, reducânduse astfel dramatic timpul de acces de la 8 15 ms la ns în tehnologiile actuale (2002)! De obicei, spaţiul virtual de adresare este împărţit în entităţi de capacitate fixă (4 64 Ko actualmente), numite pagini. O pagină poate fi mapată în MP sau pe disc.

49 Arhitectura sistemului ierarhizat de memorie 53 Figura 2.9. Maparea adreselor virtuale în adrese fizice În general, prin mecanismele de MV, MP conţine paginile cel mai recent accesate de către un program, ea fiind după cum am mai arătat, pe post de cache între CPU şi discul hard. Transformarea adresei virtuale emisă de către CPU întro adresă fizică (existentă în spaţiul MP) se numeşte mapare sau translatare. Aşadar mecanismul de MV oferă o funcţie de relocare a programelor (adreselor de program), pentru că adresele virtuale utilizate de un program sunt relocate spre adrese fizice diferite, înainte ca ele să fie folosite pentru accesarea memoriei. Această mapare permite aceluiaşi program să fie încărcat şi să ruleze oriunde ar fi încărcat în MP, modificările de adrese realizându-se automat prin mapare (fără MV un program depinde de obicei în execuţia sa de adresa de memorie unde este încărcat). MV este un concept deosebit de util în special în cadrul sistemelor de calcul multiprogramate care - de exemplu prin time-sharing - permit execuţia cvasi-simultană a mai multor programe (vezi sistemul de operare WINDOWS 2000, NT, Unix, Ultrix etc.). Fiecare dintre aceste programe are propriul său spaţiu virtual de cod şi date ( având alocate un număr de pagini virtuale), dar în realitate toate aceste programe vor partaja aceeaşi MP, care va conţine dinamic, pagini aferente diverselor procese. Paginile vor fi

50 Arhitectura sistemului ierarhizat de memorie 54 dinamic încărcate de pe disc în MP respectiv evacuate din MP pe disc (spre a permite încărcarea altora, mai proaspete ). Când o pagină accesată nu se găseşte în MP, ea va trebui adusă prin declanşarea unui mecanism de excepţie, de pe disc. Acest proces analogul miss-urilor de la cache-uri se numeşte page fault (PF). Evenimentul PF va declanşa un mecanism de excepţie care va determina intrarea într-o subrutină de tratare a evenimentului PF. Aici prin software deci se va aduce de pe disc în MP pagina dorită după ce, fireşte, în prealabil s-a evacuat eventual o altă pagină din MP. Acest proces este unul de lungă durată, necesitând câteva ms bune la ora actuală. Având în vedere multitaskingul, MV trebuie să asigure şi mecanismul de protecţie a programelor (ex. să nu permită unui program utilizator să scrie zona de date sau cod a sistemului de operare sau a altui program, să nu permită scrierea într-o pagină accesabilă numai prin citire etc.). În implementarea MV trebuie avute în vedere următoarele aspecte importante: paginile să fie suficient de mari (4 ko 16 ko 64 ko) astfel încât să compenseze timpul mare de acces la disc (9 12 ms). organizări care să reducă rata de evenimente PF, rezultând un plasament flexibil al paginilor în memorie (MP) PF-urile trebuie tratate prin software şi nu prin hardware (spre deosebire de miss-urile în cache-uri), timpul de acces al discurilor permitând lejer acest lucru. scrierile în MV se fac după algoritmi tip Write Back şi nu Write Through (ar consuma timp enorm).

51 Arhitectura sistemului ierarhizat de memorie 55 Figura Translatare adresă virtuală în adresă fizică Obs. Fiecare program are propria sa tabelă de pagini care mapează spaţiul virtual de adresare al programului într-un spaţiu fizic, situat în M.P. Tabela de pagini + PC + registrele microprocesorului formează starea unui anumit program. Programul + starea asociată caracterizează un anumit proces (task). Un proces executat curent este activ, altfel el este inactiv. Comutarea de taskuri implică inactivarea procesului curent şi activarea altui proces, inactiv până acum rezultând deci ca fiind necesară salvarea/restaurarea stării proceselor. Desigur, sistemul de operare (S..) trebuie doar să reâncarce registrul pointer al adresei de bază a paginii (PTR) pentru a pointa la tabela de pagini aferentă noului proces activ. Excepţia Page Fault (P.F.) Apare în cursul mecanismului de translatare a adresei virtuale în adresă fizică, dacă bitul P = 0. Ca urmare, printr-o procedură de excepţie se

52 Arhitectura sistemului ierarhizat de memorie 56 dă controlul unui handler al S.. în vederea tratării. Aici S.. va trebui să decidă ce pagină din M.P. va trebui evacuată în vederea încărcării noii pagini de pe disc. În general, ca principiu, se poate merge pe ideea LRU ( Least Recently Used ), adică va fi evacuată pagina care nu a mai fost accesată de către CPU de cel mai mult timp (se merge deci implicit pe principiul localităţii temporale). Exemplu: CPU a accesat în ordine paginile: 10,12,9,7,11,10 iar acum accesează pagina 8 care nu este prezentă în MP evacuează pagina 12! Dacă următorul acces generează PF evacuează pagina 9, ş.a.m.d. Obs. Unele maşini (ex. Pentium) implementează în tabela de pagini câte un bit de referinţă pentru fiecare pagină. Acest bit este setat la fiecare accesare a acelei pagini. S.. şterge periodic aceşti biţi nu înainte de a le memora starea astfel încât să implementeze pentru fiecare pagină un contor; astfel, bazat pe starea de moment a acestor contoare, se stabileşte care pagină va fi evacuată. Se realizează astfel o implementare simplificată, bazată pe politica LRU. Scrierile în MP se desfăşoară după următoarele principii: strategie similară cu cea de tip write-back de la memoriile cache (copyback) se adaugă un Dirty Bit (D) în tabela de pagini pentru fiecare pagină. Bitul D e setat la fiecare scriere în pagină la evacuare, o pagină având bitul D=0, nu are rost să se evacueze efectiv pe disc pierdere mare de timp minimizare scrieri! Translation Lookaside Buffers (TLB) Prin paginare, fiecare acces la o dată necesită 2 accese la memorie: unul pentru obţinerea adresei fizice din tabela de pagini, iar celălalt pentru accesarea propriu-zisă a datei în M.P. În vederea reducerii acestui timp de acces (dublu), tabela de pagini este caşată (memorată parţial) în CPU. Memoria cache care memorează maparea tabelei de pagini se numeşte TLB (Translation Lookaside Buffer). Ca orice cache, TLB-ul poate avea diferite grade de asociativitate. Există evacuări/încărcări între TLB şi tabela de pagini din M.P. Deoarece TLB-ul este implementat în general on-chip, capacitatea sa este relativ mică ( intrări), în comparare cu tabela de pagini care are 1 4 M intrări. De obicei TLB-ul se implementează complet asociativ (full-associative), pentru a avea o rată de miss scăzută (0,01 % 0,1 % 1

53 Arhitectura sistemului ierarhizat de memorie 57 %). Missurile în TLB se pot rezolva atît prin protocol hardware cât şi printrun handler software. Figura Relaţia TLB - cache într-un microsistem DEC 3100 (microprocesor MIPS-R2000) Obs. Ar fi mai rapid dacă s-ar adresa cache-ul cu adresa virtuală (cache-uri virtuale) şi nu cu cea fizică. Probleme/soluţii în acest sens sunt comutări taskuri- Process Identifier, analiză antialias, "page colouring" etc. O soluţie simplă şi imediată ar consta în adresarea cache-ului cu biţii P care sunt nemodificaţi prin procesul de translatare. Desigur în acest caz este necesar ca dimensiunea cache dimensiunea paginii.

54 Arhitectura sistemului ierarhizat de memorie 58 Protecţia în sistemele cu M.V. Deşi fiecare proces are propriul său spaţiu virtual de adresare, memoria fizică (MP) este partajată între mai multe procese (procese utilizator, S, driverele I/O etc.). Desigur, trebuie să se controleze strict accesul unui proces în zonele de cod şi date ale altui proces rezultând necesitatea protecţiei la scrieri/citiri. De exemplu, numai S.. trebuie să poată modifica tabelele de pagini aferente diferitelor procese. În vederea implementării protecţiilor, hardul trebuie să asigure cel puţin următoarele 3 condiţii: 1. Cel puţin 2 moduri distincte de rulare a unui program:modul supervizor (kernel, executiv) în care un proces poate să execute orice instrucţiuni şi să acceseze oricare resurse şi respectiv modul user în care un proces are o mulţime de restricţii legate de protecţia şi securitatea sistemului. 2. Să existe o parte a stării CPU în care un proces user să nu poată scrie. De exemplu: biţi de stare user/kernel, registrul PTR, bitul validare/invalidare, excepţii, pagini kernel (ACCES) etc. Posibilitatea unui proces user să scrie astfel de resurse ar determina S.. (proces supervizor) să nu poată controla procesele user. 3. Mecanismele de tranziţie a procesorului din modul supervizor în modul user şi invers. Tranziţia user-supervizor în modul user se poate face printr-o excepţie (întrerupere) sau printr-o instrucţiune specială de tip SYSTEM CALL, care transferă controlul la o adresă dedicată din spaţiul de cod supervizor (CALL GATE la Pentium). Se salvează PC-ul şi contextul procesului curent şi CPU e plasat în modul de lucru anterior (user aici). De asemenea, din modul supervizor se poate trece în modul user prin simpla modificare a biţilor de mod (e permis!). De exemplu, să presupunem că un proces P2 doreşte să îi transmită (citire) anumite date, printr-o pagină proprie, unui alt proces P1. Pentru asta, P2 ar putea apela o rutină a S.. (printr-un SYSTEM CALL), care la rîndul ei (fiind privilegiată!) va crea o intrare în tabela de pagini a lui P1 care să se mapeze pe pagina fizică pe care P2 doreşte s-o pună la dispoziţie. S.. (supervizor) poate să utilizeze bitul Write Protection pentru a împiedica procesul P1 să altereze respectiva pagină. Şi alţi biţi de control de tip drepturi de acces" în pagină pot fi incluşi în tabela de pagini şi în TLB.

55 Arhitectura sistemului ierarhizat de memorie 59 Obs. În cazul unei comutări de taskuri de la procesul P1 la procesul P2, TLB-ul trebuie golit din 2 motive: în caz de hit P2 să nu utilizeze paginile lui P1 şi respectiv să se încarce în TLB intrările din tabela de pagini a procesului P2 (pointată de noul PTR). Asta se întâmplă numai dacă P1 şi P2 folosesc VPN-uri identice (biţii din adrese virtuală). Pentru a nu goli TLB-ul prea des, se preferă adăugarea la tag-ul acestuia a unui câmp numit PID ( Process Identifier identificator al procesului), care va contribui corepunzător la HIT. Această informaţie (PID) este ţinută de obicei într-un registru special, ce va fi încărcat de către S.. la fiecare comutare de taskuri. Ca şi consecinţă se evită în majoritatea cazurilor golirea (şi implicit reumplerea!) TLB-ului. În concluzie, foarte succint, protecţia este asigurată în principal prin: moduri de lucru CPU de diferite nivele de privilegiu control strict al S.. asupra tranziţiilor din user în kernel (prin CALL GATES-uri - porţi de apel - la o anumită adresă determinată din spaţiul de cod kernel) protecţie a paginilor prin drepturi de acces la pagină (read only, read/write etc). Tratarea miss-urilor în TLB şi a PF-urilor Pe durata procesului de translatare a adresei virtuale în adresă fizică pot să apară 2 evenimente de excepţie: 1. TLB miss, dar pagina accesată este prezentă în memoria fizică (M.P.) 2. Page Fault (PF), adică TLB miss urmat de faptul că pagina dorită nu este prezentă în tabela de pagini rezidentă în M.P. (bit P=0). Un TLB miss generează de obicei o procedură hardware de aducere a numărului paginii fizice din tabela de pagini. Această operaţie se poate implementa prin hardware, ea durând un timp relativ scurt (cca tacte CPU). Tratarea PF în schimb, necesită un mecanism de tratare al excepţiei care să întrerupă procesul activ, să transfere controlul rutinei de tratare PF (S..) şi apoi să redea controlul procesului întrerupt. PF va fi recunoscut pe parcursul ciclilor de acces la memorie. Cum instrucţiunea care a cauzat PF trebuie reluată, rezultă că trebuie salvat în stivă (automat) PC-ul aferent acesteia. Pentru asta, există un registru special EPC (Exception PC), întrucât PC-ul propriu-zis poate să fie mult incrementat sau chiar complet altul (din motive de prefetch, branch-uri etc.). Mai apoi, printr-un sistem de

56 Arhitectura sistemului ierarhizat de memorie 60 întreruperi (vectorizate) se dă controlul rutinei de tratare din cadrul S.. Aici, se află cauza excepţiei prin consultarea registrului cauză excepţie iar apoi se salvează întreaga stare (context) a procesului întrerupt (regiştrii generali, PTR, EPC, registri cauză excepţie etc.). Dacă PF-ul a fost cauzat de un fetch sau write data, adresa virtuală care a cauzat PF trebuie calculată din însăşi formatul instrucţiunii pe care PF s-a produs (PC-ul aferent acesteia e memorat în EPC), de genul base + offset. Odată ştiută adresa virtuală care a cauzat PF, rutina de tratare a S.. aduce pagina de pe disc în MP, după ce mai întâi a evacuat (LRU) o pagină din MP pe disc. Cum accesul pe disc durează mii de tacte, uzual S.. va activa un alt proces pe această perioadă. Segmentarea Constituie o altă variantă de implementare a MV, care utilizează în locul paginilor de lungime fixă, entităţi de lungime variabilă zise segmente. În segmentare, adresa virtuală este constituită din 2 cuvinte: o bază a segmentului şi respectiv un deplasament (offset) în cadrul segmentului. Datorită lungimii variabile a segmentului (de ex. 1 octet 2³² octeţi la arhitecturile Intel Pentium), trebuie făcută şi o verificare a faptului că adresa virtuală rezultată (baza + offset) se încadrează în lungimea adoptată a segmentului. Desigur, segmentarea oferă posibilităţi de protecţie puternice şi sofisticate a segmentelor. Pe de altă parte, segmentarea induce şi numeroase dezavantaje precum: 2 cuvinte pentru o adresă virtuală, necesare având în vedere lungimea variabilă a segmentului. Asta complică sarcina compilatoarelor şi a programelor încărcarea segmentelor variabile în memorie mai dificilă decât la paginare fragmentare a memoriei principale (porţiuni nefolosite) frecvent, trafic ineficient MP-disc (de exemplu pentru segmente mici, transferul cu discul e complet ineficient accese la nivel de sector = 512 octeti) Există în practică şi implementări hibride segmentare paginare.

57 3. PROCESOARE PIPELINE SCALARE CU SET OPTIMIZAT DE INSTRUCŢIUNI [7] 3.1. MODELUL RISC. GENEZĂ ŞI CARACTERISTICI GENERALE Microprocesoarele RISC (Reduced Instruction Set Computer) au apărut ca o replică la lipsa de eficienţă a modelului convenţional de procesor de tip CISC (Complex Instruction Set Computer). Multe dintre instrucţiunile maşină ale procesoarelor CISC sunt foarte rar folosite în softul de bază, cel care implementează sistemele de operare, utilitarele, translatoarele, etc. Lipsa de eficienţă a modelului convenţional CISC a fost pusă în evidenţă prin anii '80 de arhitecturi precum INTEL 80x86, MOTOROLA 680x0, iar in domeniul (mini)sistemelor în special de către arhitecturile VAX-11/780 şi IBM - 360,370, cele mai cunoscute la acea vreme. Modelele CISC sunt caracterizate de un set foarte bogat de instrucţiuni - maşină, formate de instrucţiuni de lungime variabilă, numeroase moduri de adresare deosebit de sofisticate, etc. Evident că această complexitate arhitecturală are o repercursiune negativă asupra performanţei maşinii. Primele microprocesoare RISC s-au proiectat la Universităţile din Stanford (coordonator prof. John Hennessy) şi respectiv Berkeley (coordonator prof. David Patterson, cel care a şi propus denumirea RISC), din California, USA (1981). Spre deosebire de CISC-uri, proiectarea sistemelor RISC are în vedere că înalta performanţă a procesării se poate baza pe simplitatea şi eficacitatea proiectului ("Keep it simple!). Strategia de proiectare a unui microprocesor RISC trebuie să ţină cont de analiza aplicaţiilor posibile pentru a determina operaţiile cele mai frecvent utilizate, precum şi optimizarea structurii hardware în vederea unei execuţii cât mai rapide a instrucţiunilor. Dintre aplicaţiile specifice sistemelor RISC se amintesc: conducerea de procese în timp real, procesare de semnale (DSP), calcule ştiinţifice cu viteză ridicată, grafică de mare performanţă, elemente de procesare în sisteme multiprocesor şi alte sisteme cu prelucrare paralelă, etc.

58 Procesoare pipeline scalare cu set optimizat de instrucţiuni 62 Caracteristicile de bază ale modelului RISC sunt următoarele: -Timp de proiectare şi erori de construcţie mai reduse decât la variantele CISC. -Unitate de comandă hardware în general cablată, cu firmware redus sau deloc, ceea ce măreşte rata de execuţie a instrucţiunilor. -Utilizarea tehnicilor de procesare pipeline a instrucţiunilor, ceea ce implică o rată teoretică de execuţie de o instrucţiune / ciclu, pe modelele de procesoare care pot lansa în execuţie la un moment dat o singură instrucţiune (procesoare scalare). -Memorie sistem de înaltă performanţă, prin implementarea unor arhitecturi avansate de memorie cache şi MMU (Memory Management Unit). De asemenea conţin mecanisme hardware de memorie virtuală bazate în special pe paginare ca şi sistemele CISC de altfel. -Set relativ redus de instrucţiuni simple, majoritatea fără referire la memorie şi cu puţine moduri de adresare. În general, doar instrucţiunile LOAD / STORE sunt cu referire la memorie (arhitectură tip LOAD / STORE). La implementările recente caracteristica de "set redus de instrucţiuni" nu trebuie înţeleasă add literam ci mai corect în sensul de set optimizat de instrucţiuni în vederea implementării aplicaţiilor propuse (în special implementării limbajelor de nivel înalt - C, Visual C++, Pascal, etc.). -Datorită unor particularităţi ale procesării pipeline (în special hazardurile pe care aceasta le implică), apare necesitatea unor compilatoare optimizate (schedulere), cu rolul de a reorganiza programul sursă pentru a putea fi procesat optimal din punct de vedere al timpului de execuţie. -Format fix al instrucţiunilor, codificate în general pe un singur cuvânt de 32 biţi, mai recent pe 64 biţi (Alpha 21164, Power PC-620, etc.). -Necesităţi de memorare a programelor mai mari decât în cazul microsistemelor convenţionale, datorită simplităţii instrucţiunilor cât şi reorganizatoarelor care pot acţiona defavorabil asupra "lungimii" programului obiect. -Set de registre generale substanţial mai mare decât la CISC-uri, în vederea lucrului "în ferestre" (register windows), util în optimizarea instrucţiunilor CALL / RET. Numărul mare de registre generale este util şi pentru mărirea spaţiului intern de procesare, tratării optimizate a evenimentelor de excepţie, modelului ortogonal de programare, etc. Registrul R0 este cablat la zero în majoritatea implementărilor, pentru optimizarea modurilor de adresare şi a instrucţiunilor. Microprocesoarele RISC scalare reprezintă modele cu adevărat evolutive în istoria tehnicii de calcul. Primul articol despre acest model de procesare a apărut în anul 1981 (David Patterson, Carlo Sequin), iar peste numai 6-7 ani toate marile firme producătoare de hardware realizau

59 Procesoare pipeline scalare cu set optimizat de instrucţiuni 63 microprocesoare RISC scalare în scopuri comerciale sau de cercetare. Performanţa acestor microprocesoare creşte în medie cu cca. 75% în fiecare an SET DE INSTRUCŢIUNI. REGIŞTRI INTERNI LA MODELUL ARHITECTURAL RISC În proiectarea setului de instrucţiuni aferent unui microprocesor RISC intervin o multitudine de consideraţii dintre care se amintesc: a). Compatibilitatea cu seturile de instrucţiuni ale altor procesoare pe care s-au dezvoltat produse software consacrate (compatibilitatea de sus în jos, valabilă de altfel şi la CISC-uri). Portabilitatea acestor produse pe noile procesoare este condiţionată de această cerinţă care vine în general în contradicţie cu cerinţele de performanţă ale sistemului. b). În cazul microprocesoarelor, setul de instrucţiuni este în strânsă dependenţă cu tehnologia folosită, care de obicei limitează sever performanţele (constrângeri legate de aria de integrare, numărul de pini, cerinţe restrictive particulare ale tehnologiei, etc.). c). Minimizarea complexităţii unităţii de comandă precum şi minimizarea fluxului de informaţie procesor - memorie. d). În cazul multor microprocesoare RISC setul de instrucţiuni maşină este ales ca suport pentru implementarea unor limbaje de nivel înalt. Setul de instrucţiuni al unui microprocesor RISC este caracterizat de simplitatea formatului precum şi de un număr limitat de moduri de adresare. De asemenea, se urmăreşte ortogonalizarea setului de instrucţiuni. Deosebit de semnificativ în acest sens, este chiar primul microprocesor RISC numit RISC I Berkeley. Acesta deţinea un set de 31 instrucţiuni grupate în 4 categorii: aritmetico-logice, de acces la memorie, de salt / apel subrutine şi speciale. Microprocesorul deţinea un set logic de 32 regiştri generali pe 32 biţi. Formatul instrucţiunilor de tip registru-registru şi respectiv de acces la memorie (LOAD / STORE) este dat în figura 3.1: Figura 3.1. Formatul instrucţiunii la Berkeley I RISC. Câmpul IMM = 0 arată că cei mai puţini semnificativi (c.m.p.s.) 5 biţi ai câmpului SOURCE2 codifică al 2-lea registru operand.

60 Procesoare pipeline scalare cu set optimizat de instrucţiuni 64 Câmpul IMM = 1 arată că SOURCE2 semnifică o constantă pe 13 biţi cu extensie semn pe 32 biţi. Câmpul SCC (Store Condition Codes) semnifică validare / invalidare a activării indicatorilor de condiţie, corespunzător operaţiilor aritmeticologice executate. În ciuda setului redus de instrucţiuni al procesorului Berkeley RISC I, acesta poate sintetiza o multitudine de instrucţiuni aparent "inexistente" la acest model. Practic nu se "pierd" instrucţiuni ci doar "opcode"- uri, şi ca o consecinţă, în plus se simplifică substanţial logica de decodificare şi unitatea de comandă. Un alt format de instrucţiuni combină ultimele 3 câmpuri ale acestui format ca un offset pe 19 biţi, în instrucţiunile de salt relativ. Cu precizarea că registrul R0 este cablat la 0, se poate arăta că practic pot fi sintetizate toate modurile de adresare de la procesorul CISC tip VAX11-780, după cum se sugerează în tabel: Mod de adresare Vax 11/780 Echivalent RISC 1 Registru Ri Ri Imediat #Literal S2 (literal pe 13 biti), IMM =1 Indexat Ri + offset Ri+S2(offset pe 13 biti) Indirect-registru (Ri) Ri+S2, S2=0 R0+S2, R0=0 Tabelul 3.1. Formatul instrucţiunii la Berkeley I RISC. În ciuda setului redus de instrucţiuni al procesorului RISC I, acesta poate sintetiza o multitudine de instrucţiuni aparent inexistente. Iată doar câteva exemple : Instrucţiune VAX 11/780 Echivalent RISC I Move registruregistru MOVL Ri, Rj ADD R0, Ri, Rj (R0+Ri Rj, R0=0, SCC=1) Comparare registruregistru CMPL Ri, Rj Sub Ri, Rj, R0 (Ri-Rj R0, SCC=1); R0=0 Clear locaţie memorie CLRL <Adresa> STL R0, (R0) S2 (Locaţie mem. (R0+S2) 0) Incrementări Decrementări INCL Ri DECL Ri ADD Ri, #1, Ri SUB Ri, #1, Ri Incărcare contor MOVL $N, Ri ADD R0, #N, Ri Complement de 1 MCOMPL Ri, Rj XOR Ri, #1, Rj Tabelul 3.2.

61 Procesoare pipeline scalare cu set optimizat de instrucţiuni 65 Instrucţiuni emulate cu ajutorul setului de instrucţiuni al procesorului RISC I Următoarele 3 formate de instrucţiuni sunt întâlnite practic în toate arhitecturile RISC studiate (DLX, Intel 860, 960, MIPS 88000, SPARC, APLHA, Power PC, HP PA etc.) : instrucţiuni registru registru (RS1, RS2, RDEST), de tip aritmetico logice cu 2 operanzi instrucţiuni registru constantă imediată (RS1, constantă, RDEST) sunt instrucţiuni de transfer, aritmetico logice, etc. instrucţiuni de ramificaţie în program (JUMP / CALL, BRANCH, etc.) O altă categorie de microprocesoare RISC reprezentative sunt cele din familia MIPS 2000 / 3000, dezvoltate iniţial la universitatea din Stanford U.S.A. La aceste procesoare există 3 formate distincte de instrucţiuni maşină : R-type, I-type şi J-type. Formatul R-type înglobează instrucţiuni aritmetico logice, de salt / apel etc. şi este prezentat mai jos : OPCODE (6) RS(5) RT(5) RD(5) SHAMT (5) FUNCT (6) Figura 3.2. Formatul R-type la procesorul MIPS R Câmpurile RS, RT şi RD specifică regiştrii sursă respectiv registrul destinaţie al instrucţiunii. Câmpul FUNCT codifică varianta de operaţie aferentă unei anumite grupe de operaţii codificate de câmpul OPCODE. Câmpul SHAMT specifică numărul poziţiilor binare cu care se face deplasarea pentru instrucţiunile de deplasare aritmetice sau logice. De ex. instrucţiunea SLL $10, $16, 8, introduce în registrul 10 conţinutul registrului 16 deplasat logic la stânga cu 8 poziţii binare. Tot în formatul R-Type se încadrează şi instrucţiuni de comparaţie. De exemplu instrucţiunea SLT $1, $2, $3 semnifică : if ($2 < $3) $1 = 1 else $1 = 0. Tot aici se încadrează şi instrucţiunea de salt indirect registru JR $31. Formatul I-type este ca în figură: OPCODE (6) RS (5) RT (5) OFFSET (16) Figura 3.3. Formatul I-type la procesorul MIPS R Acest format este specific instrucţiunilor LOAD / STORE care utilizează modul de adresare indexat. De exemplu o instrucţiune de încărcare: LW $8, ASTART ($9) (incarcă în registrul 8 locaţia de memorie de la adresa indexată). Tot aici se incadrează şi instrucţiunile de salt condiţionat pe diverse condiţii precum:

62 Procesoare pipeline scalare cu set optimizat de instrucţiuni 66 BEQ $1, $2, ADR sau BNE 41, $2, ADR. OBS. Distincţia între formatele R şi I se face prin câmpul de OPCODE. Formatul J type este specific instrucţiunilor de salt. OPCODE (6) ADRESĂ (26) Figura 3.4. Formatul J-type la procesorul MIPS R De exemplu J 10000, salt la adresa Instrucţiunea Jump and Link : JAL ADR determină $31 = PC + 4 iar apoi salt la adresa ADR. De remarcat simplitatea şi regularitatea setului de instrucţiuni. Câmpurile îşi păstrează locurile în cele 3 tipuri de formate de instrucţiuni, ceea ce determină simplificarea decodificatorului de instrucţiuni al procesorului. Desigur însă că adresele şi constantele din cadrul instrucţiunilor sunt limitate de lungimea fixă a câmpurilor aferente. De exemplu apelul / revenirea la / din o subrutină se face prin instrucţiunile JAL Subr / JR $31 respectiv, evitându-se astfel memoria stivă. Ce se întâmplă însă în cazul a 3 rutine imbricate? Considerând 3 rutine A, B, C imbricate, situaţia se rezolvă elegant ca în continuare: A: JAL B B: ADD $29, $29, $24 SW $31, 0($29) JAL C C: LW $31, 0($29) SUB $29,$29,$24 JR $31 JR $31 Şi la acest microprocesor, setul instrucţiunilor maşină a fost proiectat ţinând cont de facilizarea implementării unor limbaje HLL (High Level Languages). Exemplificăm prin implementarea următoarei secvenţe în limbajul C : switch (k) { case 0: f = i + j; break case 1: f = g + h; break case 2: f = g h; break case 3: f= i j; break }

63 Procesoare pipeline scalare cu set optimizat de instrucţiuni 67 Considerând variabilele f, g, h, i, j, k stocate respectiv în regiştrii 16, 17, 18, 19, 20, 21 şi că $10 = 4 avem următoarea implementare în limbaj maşină MIPS a secvenţei C anterioare : LOOP: MULT $9, $10, $21; $9 k*4 LW $8, JT ($9) JR $8 L0: ADD $16, $19, $20 J EXIT L1: ADD $16, $17, $18 J EXIT L2: SUB $16, $17, $18 J EXIT L3: SUB $16, $19, $20 J EXIT EXIT: Menţionăm că la adresele JT, JT + 4, JT + 8, JT + 12 în memorie avem stocate etichetele L0, L1, L2 şi L3. O variantă a ideii de RISC este modelul Single Instruction Computer (SIC) de procesor, care execută o singură instrucţiune cablată. De exemplu un procesor SIC care ştie să execute doar instrucţiunea Substract and Branch if Negative (SBN) după următoarea regulă: SBN a, b, c; MEM MEM (a) MEM(b) if MEM (a) < 0 go to c Prin această instrucţiune se pot emula multe alte instrucţiuni mai complicate. De exemplu o instrucţiune de tipul MEM (a) MEM (b) s-ar emula pe un procesor SIC SBN astfel: START: SBN temp, temp, +1 SBN temp, a, +1 SBN b, b, +1 SBN b, temp, +1 Este surprinzător că printr-o singură instrucţiune se pot emula principalele instrucţiuni ale unui procesor mai matur. Ideea a fost de altfel reluată de arhitecţii anilor 80, care au introdus conceptul de TTA (vezi capitolul următor). Încă o dovadă că procesoarele SIC, RISC, superscalare,

64 Procesoare pipeline scalare cu set optimizat de instrucţiuni 68 VLIW, EPIC, vectoriale etc. au repus în discuţie lucruri absolut fundamentale dar nefundamentate satisfăcător prin implementările CISC. Regândirea modurilor optimale de proiectare a procesoarelor numerice a stratat abia la începutul anilor 1980 odată cu cercetările legate de conceptul de RISC. Potenţial, programele RISC pot conţine mai multe CALL-uri decât cele convenţionale, în principal pentru că instrucţiunile complexe implementate în procesoarele CISC vor fi subrutine în cazul procesoarelor RISC. Din acest motiv procedura CALL / RET se impune a fi cât mai rapidă în procesarea RISC. Modelul utilizării registrelor în fereastre îndeplineşte acest deziderat prin reducerea traficului de date cu memoria sistem (Berkeley I RISC, SUN-SPARC, etc.) Principiul de lucru constă în faptul că fiecare instrucţiune CALL alocă o nouă fereastră de registre pentru a fi utilizată de procedura apelată, în timp ce o instrucţiune RET va restaura vechea fereastră de registre. Se consideră spre exemplificare 3 procese soft, care se apelează imbricat ca în figura următoare (figura.3.5): Figura 3.5. Lucrul în ferestre de registre Statistici deosebit de serioase arată că în cadrul implementărilor de limbaje HLL (High Level Languages) instrucţiunile CALL / RET sunt frecvent folosite şi totodată cele mai mari consumatoare de timp (ocupă între 5%-45% din referirile la memorie). Fiecare proces are alocată o fereastră de regiştri constând în 3 seturi distincte : HIGH, LOCAL şi LOW. Registrele globale R0 - R9 conţin parametrii globali ai proceselor soft. Aceşti regiştri sunt comuni tuturor proceselor şi nu se salvează / restaurează

65 Procesoare pipeline scalare cu set optimizat de instrucţiuni 69 niciodată. Regiştrii locali R16 - R25 sunt utilizaţi pentru memorarea scalarilor locali ai procesului curent. O instrucţiune CALL determină ca registrele LOW din procesul master apelant să devină registre HIGH în procesul SLAVE apelat. Odată cu schimbarea ferestrelor, o instrucţiune CALL memorează registrul PC într-un anumit registru al noii ferestre. O instrucţiune RET determină o acţiune reciprocă, adică regiştrii HIGH ai procesului curent vor deveni regiştrii LOW pentru procesul MASTER în care se revine. În regiştrii LOW procesul MASTER transmite automat parametrii spre procesul SLAVE, respectiv din aceşti regiştri procesul MASTER curent preia rezultatele de la procesul SLAVE apelat. În regiştrii HIGH procesul curent memorează rezultatele, respectiv din aceşti regiştri procesul curent preia parametrii transmişi de către procesul MASTER apelant. Se observă că aceste comutări de ferestre au drept principal scop eliminarea stivei şi deci a timpului consumat cu accesarea acesteia. Referitor la cele de mai sus apar 2 tipuri de excepţii ca fiind posibile: - "window overflow" (WO) poate să apară după o instrucţiune CALL în care schimbarea setului de regiştri LOW ai procesului curent în regiştrii HIGH ai procesului viitor devine imposibilă datorită numărului limitat de regiştri generali implementaţi; - "window underflow" (WU) poate să apară după o instrucţiune RET care determină ca schimbarea regiştrilor HIGH ai procesului curent în regiştrii LOW ai procesului viitor să devină imposibilă. Dintre microprocesoarele RISC consacrate, cele din familia SPARC (sistemele SUN) au implementat un set de maxim 32 ferestre a câte 32 regiştri fiecare. Numărul mare de regiştri generali necesari pentru implementarea conceptului de "register windows" implică reducerea frecvenţei de tact a procesorului, fapt pentru care conceptul nu este implementat decât rar în microprocesoarele RISC comerciale. Studii statistice realizate încă din perioada de pionierat de către Halbert şi Kessler, arată că dacă procesorul deţine 8 ferestre de regiştri, excepţiile WO şi WU vor apare în mai puţin de 1% din cazuri. Evident că supraplasarea trebuie evitată în cadrul rutinei de tratare a excepţiei prin trimiterea / recepţionarea parametrilor proceselor în / din buffere de memorie dedicate (stive). De precizat că setul larg de regiştri generali este posibil de implementat la microprocesoarele RISC prin prisma tehnologiilor VLSI (Very Large Scale Integration) disponibile (HC-MOS, ECL, GaAs, etc.), întrucât unitatea de comandă, datorită simplităţii ei, ocupă un spaţiu relativ restrâns (la Berkeley RISC I de ex., ocupa doar aproximativ 6% din aria de integrare). Restul spaţiului rămâne disponibil pentru implementarea unor

66 Procesoare pipeline scalare cu set optimizat de instrucţiuni 70 suporturi de comunicaţie interprocesor (ex. transputere), memorii cache, logică de management al memoriei, set regiştri generali extins, arii sistolice specializate de calcul (la DSP-uri, neuroprocesoare), etc DUALITATEA ARHITECTURĂ APLICAŢIE: IMPLEMENTAREA GESTIUNII STIVELOR DE DATE ASOCIATE FUNCŢIILOR C După cum se ştie, stiva de date asociată unei funcţii scrise în limbajul C reprezintă o zonă de memorie unde sunt stocate toate variabilele locale şi parametrii aferenţi respectivei funcţii ( activation record ). Fiecare funcţie C are propriul context păstrat în această structură de date specială. Stiva de date se asociază în mod dinamic fiecărei funcţii în curs. Aşadar, o funcţie poate avea la un moment dat mai multe stive (instanţe), doar una fiind însă activă. Spre exemplu, recursivitatea se poate implementa facil în C tocmai datorită acestei caracteristici. Structura stivei de date asociate unei funcţii C este prezentată în figura următoare, corespunzător secvenţei de program de mai jos. int NoName (int a, int b) { int w,x,z; /* Corpul funcţiei */ }... return y;

67 Procesoare pipeline scalare cu set optimizat de instrucţiuni 71 Figura Structura stivei de date asociate funcţiei NoName RETURN VALUE: aici se plasează valoarea variabilei y, chiar înainte de revenirea din funcţie. Acest câmp există şi dacă funcţia nu ar returna practic nici o valoare. RETURN ADDRESS (PC): reprezintă PC-ul de revenire în funcţia apelantă. DYNAMIC LINK: memorează adresa de început a stivei de date aferente funcţiei apelante. În continuare, se va considera că registrul R6 va conţine adresa de început a stivei de date asociată funcţiei respective. Aşadar funcţia NoName procesează asupra parametrilor trimişi de către funcţia apelantă (a,b) respectiv asupra variabilelor locale ale acesteia (w,x,y). Fireşte, ea trimite rezultatele (y) către funcţia apelantă prin stiva de date curentă. În continuare se consideră că atunci când funcţia NoName este apelată, pointerul la stivele de date (R6, aici) va pointa la începutul stivei de date aferente funcţiei. Pentru a înţelege implementarea apelurilor/revenirilor funcţiilor, se consideră următorul exemplu de program: main() { int a; int b;..

68 Procesoare pipeline scalare cu set optimizat de instrucţiuni 72 b=noname(a,10);.. } int NoName(int a, int b) { int w,x,y; /* Corpul funcţiei */... return y; } Stiva de date începe la o locaţie de memorie determinată de către proiectanţii sistemului de operare şi creşte înspre adrese crescătoare. Execuţia programului începe cu un apel al sistemului de operare către funcţia main. În acest punct, stiva datelor funcţiei main se structurează în memorie, iar registrul R6 pointează la începutul ei. În translatarea apelului unei funcţii, compilatorul generează automat cod maşină pentru a înscrie o stivă de date în memorie. În translatarea revenirii dintr-o funcţie apelată în funcţia apelantă, compilatorul generează automat cod pentru preluarea stivei de date din memorie. Apelul şi revenirea se fac în 4 paşi, aşa cum se prezintă în continuare : 1) Apelul funcţiei NoName Se face prin asignarea b=noname(a,10); Stiva de date a funcţiei main() respectiv a funcţiei NoName(a,10) sunt prezentate în figura următoare.

69 Procesoare pipeline scalare cu set optimizat de instrucţiuni 73 Figura 3.7. Stivele de date asociate funcţiilor main() şi NoName(a,10) Secvenţa compilată a apelului funcţiei NoName este următoarea: ld R8, (R6)3; R8 a st R8, (R6)8; a Stiva NoName and R8, (R8), #0 ;R8 0 add R8, R8, #10; R8 10 st R8, (R6)9; (b=10) Stiva NoName st R6, (R6)7; (R6)main Stiva NoName (Dynamic Link) add R6, R6, #5; R6 (R6) +5, actualizare nou început al stivei de date jsr NoName; apel funcţie, R7PCnext şi PC(NoName) PCnext: ld R8, (R6)5 st R8, (R6)4

70 Procesoare pipeline scalare cu set optimizat de instrucţiuni 74 2) Startarea funcţiei apelate (NoName) Începe cu instrucţiunea care salvează în stiva de date a funcţiei NoName adresa de revenire în funcţia principală main(). Adresa de revenire se află stocată în registrul R7 (conţine adresa următoare a instrucţiunii JSR NoName) st R7, (R6)1 3) Sfârşitul funcţiei apelate (NoName) ld R8, (R6)7 st R8, (R6)0; ld R7, (R6)1; ld R6, (R6)2; RET; Se memorează valoarea lui y în RET VALUE din stiva de date R7 RET ADDRESS R6 adresa de început a stivei de date aferente funcţiei main (). PC adresa de revenire în funcţia main(). 4) Revenirea în funcţia apelantă (main) JSR NoName; pe această instrucţiune se face revenirea (la finele execuţiei acesteia) PCnext: ld R8, (R6)5; R8valoarea lui y din funcţia NoName st R8, (R6)4; se face asignarea : b=noname(a,10). Obs.: Stivele de date asociate funcţiilor C sunt structuri de tip tablou, având o adresă de bază stocată în registrul R6 şi un număr (variabil) de elemente. Având în vedere frecvenţa deosebită a accesării acestor structuri de date, modul de adresare indexat (R bază + offset) este esenţial în facilitarea manipulării datelor prin aceste structuri de tip tablou IMPLEMENTAREA RECURSIVITĂŢII

71 Procesoare pipeline scalare cu set optimizat de instrucţiuni 75 Se consideră şirul recurent liniar omogen de ordinul 2 cunoscut sub numele de şirul lui Fibonacci: Fibo(n) = Fibo(n-1) + Fibo(n-2), Fibo(1) = Fibo(0) = 1 O implementare C recursivă a calcului elementului Fibo(n) din cadrul acestui şir recurent este prezentată mai jos: #include<stdio.h> int Fibo(int n); main () { int in; int numar; printf( Care termen din şir? ); scanf( %d, &in); numar = Fibo (in); printf( Termenul are valoarea %d\n, numar); } int Fibo(int n) { if (n = = 0 n = = 1) return 1; else return (Fibo(n-1) + Fibo(n-2)); } Esenţa implementării recursivităţii constă în manipularea stivelor de date asociate funcţiilor dinamice (adică funcţiilor în curs de execuţie la un moment dat). În continuare se prezintă, la nivel de cod obiect, implementarea funcţiei Fibo (int n), cu referire la stivele de date accesate.

72 Procesoare pipeline scalare cu set optimizat de instrucţiuni 76 Figura 3.8. Stiva de date asociată funcţiei Fibo(n) Fibo: st R7, (R6)1; salvează PC revenire în stiva de date ld R8, (R6)3; R8 valoare n brz Fib_end add R8,R8, # -1 brz Fib_end ld R8, (R6)3; R8 n add R8,R8, # -1; R8 n-1 st R8, (R6)8; pune (n-1) ca parametru în stiva funcţiei Fibo(n-1) st R6, (R6)7; pune adresa de început a stivei funcţiei Fibo(n) în stiva funcţiei Fibo(n-1) add R6, R6,#5; pune în R6 noua adresă de început aferentă stivei de date a lui Fibo(n-1) JSR Fibo; apel funcţie Fibo (recursiv) ld R8, (R6)5; R8 valoarea returnată de Fibo (n-1) st R8, (R6)4; memorează variabila locală aferentă stivei de date a lui Fibo (n) ld R8, (R6)3; R8 (n-1) add R8, R8, #-1; R8 (n-2)

73 Procesoare pipeline scalare cu set optimizat de instrucţiuni 77 st R8, (R6)8 st R6, (R6)7 add R6, R6, #5; JSR Fibo; ld R8, (R6)5; ld R1, (R6)4; add R8, R8, R1; st R8, (R6)0; ld R6, (R6)2; RET Fib_end: and R8, R8, #0 add R8, R8, #1 st R8, (R6)0 ld R6, (R6)2 RET pregăteşte stiva de date a lui Fibo (n-2) apel recursiv R8 Fibo (n-2) R1 Fibo (n-1) R8 Fibo (n-1) + Fibo (n-2) Fibo (n) RET VALUE revenire în stiva precedentă Obs: Legătura între arhitectura unui microprocesor si aplicaţiile scrise în limbaje de nivel înalt este una complexă şi extrem de subtilă. Există microarhitecturi de calcul optimizate în mod special în vederea rulării eficiente a unor clase de aplicaţii bine precizate scrise în anumite limbaje de nivel înalt (ex. microprocesoare Java) ARHITECTURA SISTEMULUI DE MEMORIE LA PROCESOARELE RISC Principalele caracteristici ale sistemului de memorie aferent unui sistem RISC sunt preyentate succint în continuare. Astfel, în general microprocesoarele RISC deţin un management intern de memorie (MMU- Memory Management Unit) în majoritatea implementărilor. MMU-ul are rolul de a translata adresa virtuală emisă de către microprocesor într-o aşa numită adresă fizică de acces la memoria principală şi respectiv de a asigura un mecanism de control şi protecţie - prin paginare sau / şi segmentare a memoriei - a accesului la memorie. În general, MMU lucrează prin paginare în majoritatea implementărilor cunoscute, oferind şi resursele hardware necesare mecanismelor de memorie virtuală. De asemenea, sistemele RISC deţin memorii cache interne şi externe cu spaţii în general

74 Procesoare pipeline scalare cu set optimizat de instrucţiuni 78 separate pentru instrucţiuni şi date (arhitecturi Harvard de memorie) şi structuri de tip DWB (Data Write Buffer) cu rol de gestionare a scrierii efective a datelor în memoria sistem, prin degrevarea totală a procesorului propriu - zis. Pentru a asigura coerenţa şi consistenţa datelor scrise în cache, acestea trebuie scrise la un moment dat şi în memoria principală. În scopul eliberării microprocesorului de acest lucru, DWB capturează data şi adresa emise de către microprocesor şi execută efectiv scrierea în memoria cache sau în cea principală, permiţând astfel microprocesorului să-şi continue activitatea fără să mai aştepte până când data a fost efectiv scrisă in memoria principală. Aşadar, DWB se comportă ca un mic procesor de ieşire lucrând în paralel cu microprocesorul. Arhitectura de principiu a memoriei unui sistem RISC este caracterizată în figura 3.9: Figura 3.9. Arhitectura de memorie tip Harvard la procesoarele RISC În afara spaţiilor separate de instrucţiuni şi date şi a procesorului de ieşire (DWB) nu există alte probleme majore specifice microprocesoarelor RISC în arhitectura sistemelor de memorie. În principiu, ierarhizarea sistemului de memorie este aceeaşi ca şi la sistemele CISC (memorii cache, memorie virtuală). Nu intrăm aici în detalii teoretice legate de organizarea cache-urilor, a mecanismelor de memorie virtuală etc., întrucât aceste probleme sunt similare cu cele de la sistemele CISC, fiind deci foarte cunoscute şi bine documentate bibliografic. Problema majoră a sistemelor de memorie pentru ambele variante constă în decalajul tot mai accentuat între performanţa microprocesoarelor

75 Procesoare pipeline scalare cu set optimizat de instrucţiuni 79 care creşte anual cu 50-75% şi respectiv performanţa tehnologică a memoriilor (latenţa) care are o rată de creştere de doar 7% pe an. Prin urmare acest "semantic gap" microprocesor - memorie reprezintă o provocare esenţială pentru îmbunătăţirea performanţelor arhitecturilor de memorie aferente arhitecturilor actuale de procesoare. În caz contrar, având în vedere frecvenţele de tact actuale ale microprocesoarelor ( MHz) şi timpii de acces ai memoriilor tip DRAM (cca. 50 ns la ora actuală ), sistemul de calcul va funcţiona practic "cu frâna de mână trasă". Cercetarea acestei interfeţe procesor - cache, într-un mod pragmatic şi cantitativ, va constitui un obiectiv major al acestei monografii PROCESAREA PIPELINE ÎN CADRUL PROCESOARELOR SCALARE Cea mai importantă caracteristică arhitecturală a acestor microprocesoare RISC scalare o constituie procesarea pipeline a instrucţiunilor şi datelor. În fapt, aproape toate celelalte caracteristici arhitecturale ale RISC-urilor au scopul de a adapta structura procesorului la procesarea pipeline. Acest concept a migrat de la sistemele mari de calcul la microprocesoare datorită progresului tehnologiei microprocesoarelor, caracterizat prin "legea lui G. Moore". Toate supercalculatoarele au implementat acest concept. Din punct de vedere istoric primul calculator pipeline viabil a fost - la acea vreme - supersistemul CDC 6600 (firma Control Data Company, şef proiect Seymour Cray,1964) DEFINIREA CONCEPTULUI DE ARHITECTURĂ PIPELINE SCALARĂ Tehnica de procesare pipeline reprezintă o tehnică de procesare paralelă a informaţiei prin care un proces secvenţial este divizat în subprocese, fiecare subproces fiind executat într-un segment special dedicat şi care operează în paralel cu celelalte segmente. Fiecare segment execută o procesare parţială a informaţiei. Rezultatul obţinut în segmentul i este transmis în tactul următor spre procesare segmentului (i+1). Rezultatul final este obţinut numai după ce informaţia a parcurs toate segmentele, la ieşirea

76 Procesoare pipeline scalare cu set optimizat de instrucţiuni 80 ultimului segment. Denumirea de pipeline provine de la analogia cu o bandă industrială de asamblare. Este caracteristic acestor tehnici faptul că diversele procese se pot afla în diferite faze de prelucrare în cadrul diverselor segmente, simultan. Suprapunerea procesărilor este posibilă prin asocierea unui registru de încărcare (latch) fiecărui segment din pipeline. Registrele produc o separare între segmente astfel încât fiecare segment să poată prelucra date separate (vezi figura 3.10). Figura Structură de procesare tip pipeline. În figura 3.10 s-au notat prin Ti - regiştrii tampon iar prin Ni - nivelele de prelucrare (combinaţionale sau secvenţiale). Este evident că nivelul cel mai lent de prelucrare va stabili viteza de lucru a benzii. Aşadar, se impune în acest caz partiţionarea unui eventual proces mai lent în subprocese cu timpi de procesare cvasiegali şi interdependenţe minime. Există 2 soluţii principiale, discutate în literatură, de a compensa întârzierile diferite pe diversele nivele de prelucrare: Figura Balansarea unei structuri pipeline prin divizarea nivelului lent

77 Procesoare pipeline scalare cu set optimizat de instrucţiuni 81 Prima soluţie, zisă de "balansare a benzii", necesită circuite suplimentare şi poate fi realizată doar cu condiţia ca sarcinile alocate respectivului nivel să poată fi descompuse, ca în figura O a doua soluţie, se bazează pe conectarea în paralel a unui alt nivel cu aceeaşi întârziere ca cel mai lent. Şi aici trebuiesc circuite suplimentare. În plus, apare problema sincronizării şi controlului nivelelor care lucrează în paralel. Soluţia aceasta este utilizată când sarcinile alocate nivelului mai lent nu mai pot fi descompuse (vezi figura 3.12). Figura Balansare prin conectarea unui nivel lent în paralel În Tact (i) informaţia se trimite spre procesare nivelului următor pe calea A. În Tact (i+1) informaţia se trimite în mod analog pe calea B, implementându-se deci o demultiplexare. Se defineşte rata de lucru R a unei benzi de asamblare ca fiind numărul de procese executate în unitatea de timp T (ciclu maşină sau tact). Considerând m posturi de lucru prin care trec n procese, rezultă că banda le va executa într-un interval de timp Dt = (m + n -1) * T. Normal, având în vedere că m*t este timpul de "setup" al benzii, adică timpul necesar terminării primului proces. Aşadar, rata de execuţie a unei benzi prin care trec n procese este: R n = n/ (m+n-1)t (3.1) Rata ideală este de un proces per ciclu, întrucât: R = lim n R n = 1/T (3.2) După cum se va arăta în continuare, această rată teoretică nu se va putea atinge în practică, nu numai datorită faptului că se prelucrează un număr finit de procese şi datorită timpului de "setup", ci mai ales datorită unor blocaje în funcţionarea normală a benzii numite hazarduri.

78 Procesoare pipeline scalare cu set optimizat de instrucţiuni PRINCIPIUL DE PROCESARE ÎNTR-UN PROCESOR PIPELINE Procesarea pipeline a instrucţiunilor reprezintă o tehnică de procesare prin intermediul căreia fazele (ciclii) aferente multiplelor instrucţiuni sunt suprapuse în timp. Se înţelege printr-o fază aferentă unei instrucţiuni maşină o prelucrare atomică a informaţiei care se desfăşoară după un algoritm implementat în hardware (firmware) şi care durează unul sau mai mulţi tacţi. În acest sens se exemplifică: faza de aducere (fetch) a instrucţiunii, faza de decodificare, faza de execuţie, faza de citire / scriere dată, etc. Arhitectura microprocesoarelor RISC este mai bine adaptată la procesarea pipeline decât cea a sistemelor convenţionale CISC, datorită instrucţiunilor de lungime fixă, a modurilor de adresare specifice, a structurii interne bazate pe registre generale, etc. Microprocesoarele RISC uzuale deţin o structură pipeline de instrucţiuni întregi pe 4-6 nivele. De exemplu, microprocesoarele MIPS au următoarele 5 nivele tipice: 1. Nivelul IF (instruction fetch) - se calculează adresa instrucţiunii ce trebuie citită din cache-ul de instrucţiuni sau din memoria principală şi se aduce instrucţiunea; 2. Nivelul RD (ID) - se decodifică instrucţiunea adusă şi se citesc operanzii din setul de regiştri generali. În cazul instrucţiunilor de salt, pe parcursul acestei faze se calculează adresa de salt; 3. Nivelul ALU - se execută operaţia ALU asupra operanzilor selectaţi în cazul instrucţiunilor aritmetico-logice; se calculează adresa de acces la memoria de date pentru instrucţiunile LOAD / STORE; 4. Nivelul MEM - se accesează memoria cache de date sau memoria principală, însă numai pentru instrucţiunile LOAD / STORE. Acest nivel pe funcţia de citire poate pune probleme datorate neconcordanţei între rata de procesare şi timpul de acces la memoria principală. Rezultă deci că într-o structură pipeline cu N nivele, memoria trebuie să fie în principiu de N ori mai rapidă decât într-o structură de calcul convenţională. Acest lucru se realizează prin implementarea de arhitecturi de memorie rapide (cache, memorii cu acces întreţesut, etc.). Desigur că un ciclu cu MISS în cache pe acest nivel ( ca şi pe nivelul IF de altfel), va determina stagnarea temporară a acceselor la memorie sau chiar a procesării interne. La scriere, problema aceasta nu se pune datorită procesorului de ieşire specializat DWB care lucrează în paralel cu procesorul central după cum deja am arătat. 5. Nivelul WB (write buffer) - se scrie rezultatul ALU sau data citită din memorie (în cazul unei instrucţiuni LOAD) în registrul destinaţie din setul de regiştri generali ai microprocesorului.

79 Procesoare pipeline scalare cu set optimizat de instrucţiuni 83 Prin urmare, printr-o astfel de procesare se urmăreşte o rată ideală de o instrucţiune / ciclu maşină ca în figura 3.13, deşi după cum se observă, timpul de execuţie pentru o instrucţiune dată nu se reduce. Figura Principiul procesării pipeline într-un procesor RISC Se observă imediat necesitatea suprapunerii a 2 nivele concurenţiale: nivelul IF şi respectiv nivelul MEM, ambele cu referire la memorie. În cazul microprocesoarelor RISC această situaţie se rezolvă deseori prin legături (busuri) separate între procesor şi memoria de date respectiv de instrucţiuni (arhitectură Harvard). Deşi această împărţire pe 5 nivele este caracteristică mai multor microprocesoare RISC, ea are o deficienţă importantă şi anume că nu orice instrucţiune trece prin toate cele 5 nivele de procesare. Astfel, nivelul MEM este exploatat doar de către instrucţiunile LOAD / STORE, nivelul ALU de către instrucţiunile aritmetico-logice şi LOAD / STORE, iar instrucţiunile de comparare sau memorare (STORE) nu folosesc nivelul WB. Probabil asemenea observaţii au determinat proiectanţii anumitor microprocesore RISC (de ex. microprocesorul HARP - Hatfield Advanced RISC Processor proiectat la Universitatea din Hertfordshire, Marea Britanie), să comprime nivelele ALU şi MEM într-unul singur. In acest caz calculul adreselor de memorie se face în nivelul RD prin mecanisme care reduc acest timp de calcul. În literatură se citează un model de procesor numit superpipeline. Acesta este caracterizat printr-un număr relativ mare al nivelelor de procesare. Desigur că în acest caz detecţia şi corecţia hazardurilor este mai dificilă, după cum se va arăta în continuare. Arhitecturile superpipeline se pretează la tehnologiile cu grade de împachetare reduse unde nu este posibilă multiplicarea resurselor hardware, în schimb caracterizate prin viteze de comutaţie ridicate (ECL, GaAs). O asemenea arhitectură caracterizează de ex. procesoarele din familia DEC (Digital Equipment

80 Procesoare pipeline scalare cu set optimizat de instrucţiuni 84 Corporation, actualmente înglobată în concernul HP) Alpha. Avantajul principal al arhitecturilor superpipeline este că permit frecvenţe de tact deosebit de ridicate ( MHz la nivelul tehnologiilor actuale, 2002), aspect normal având în vedere super - divizarea stagiilor de procesare STRUCTURA PRINCIPIALĂ A UNUI PROCESOR RISC În continuare se prezintă o structură hardware de principiu a unui procesor RISC compatibil cu modelul de programare al microprocesorului RISC Berkeley I anterior prezentat. De remarcat că structura permite procesarea pipeline a instrucţiunilor, adică atunci când o instrucţiune se află într-un anumit nivel de procesare, instrucţiunea următoare se află în nivelul anterior. Stagiile de interconectare ale nivelelor structurii (IF / ID, ID / EX, EX / MEM, MEM / WB) sunt implementate sub forma unor regiştri de încărcare, actualizaţi sincron cu fiecare nou ciclu de procesare. Memorarea anumitor informaţii de la un nivel la altul este absolut necesară, pentru ca informaţiile conţinute în formatul instrucţiunii curente să nu se piardă prin suprapunerea fazelor de procesare. În acest sens, să ne imaginăm de exemplu ce s-ar întâmpla dacă câmpul DEST nu ar fi memorat succesiv din nivel în nivel şi rebuclat la intrarea setului de regiştri generali (vezi figura 3.14). Utilitatea acestui câmp devine oportună abia în faza WB când şi data de înscris în setul de regiştri generali devine disponibilă (cazul instrucţiunilor aritmetico-logice sau STORE). Să remarcăm că setul de regiştri generali trebuie să permită simultan două citiri şi o scriere. Schema internă a unui astfel de set de regiştri generali (REGISTER FILE), de tip multiport (2 porturi de citire şi unul de scriere), este prezentată în cele 3 figuri următoare.

81 Procesoare pipeline scalare cu set optimizat de instrucţiuni 85

82 Procesoare pipeline scalare cu set optimizat de instrucţiuni 86

83 Procesoare pipeline scalare cu set optimizat de instrucţiuni 87 Revenind la Figura 3.14, multiplexorul de la intrarea ALU are rolul de a genera registrul sursă 2, în cazul instrucţiunilor aritmetico-logice, respectiv indexul de calcul adresă (constantă pe 13 biţi cu extensie semn), în cazul instrucţiunilor LOAD / STORE. Sumatorul SUM 2 calculează adresa de salt în cazul instrucţiunilor de salt (branch) după formula: PCnext = PC + Ext.semn(IR18-0) (2.3.)

84 Procesoare pipeline scalare cu set optimizat de instrucţiuni 88 Figura Schema de principiu a unui procesor RISC Multiplexorul 2:1 de la ieşirea nivelului MEM / WB multiplexează rezultatul ALU în cazul unei instrucţiuni aritmetico-logice, respectiv data citită din memoria de date în cazul unei instrucţiuni LOAD. Ieşirea acestui multiplexor se va înscrie în registrul destinaţie codificat în instrucţiune. Evident că întreaga structură este comandată de către o unitate de control. Detalii despre proiectarea unei asemenea unităţi sunt date de exemplu în cap PROBLEMA HAZARDURILOR ÎN PROCESOARELE RISC Hazardurile constituie acele situaţii care pot să apară în procesarea pipeline şi care pot determina blocarea (stagnarea) procesării, având deci o influenţă negativă asupra ratei de execuţie a instrucţiunilor. Conform unei clasificări consacrate aceste hazarduri sunt de 3 categorii : hazarduri structurale, de date şi de ramificaţie.

85 Procesoare pipeline scalare cu set optimizat de instrucţiuni HAZARDURI STRUCTURALE (HS): PROBLEME IMPLICATE ŞI SOLUŢII Sunt determinate de conflictele la resurse comune, adică atunci când mai multe procese simultane aferente mai multor instrucţiuni în curs de procesare, accesează o resursă comună. Pentru a le elimina prin hardware, se impune de obicei multiplicarea acestor resurse. De exemplu, un procesor care are un set de regiştri generali de tip uniport şi în anumite situaţii există posibilitatea ca 2 procese să dorească să scrie în acest set simultan. Se prezintă mai jos (figura 3.15) o structură ALU implementată la microprocesorul RISC superscalar HARP care permite 4 operaţii ALU simultane. Prin partiţionarea timpului afectat nivelului WB în două, în cadrul acestui nivel se pot face două scrieri (în prima jumătate a nivelului WB se înscrie în setul de regiştri conţinutul căii A, iar în a doua parte a nivelului WB se înscrie conţinutul căii B). În principiu, un astfel de procesor poate să execute 4 instrucţiuni simultan cu condiţia ca numai două dintre ele să aibă nivelul WB activ. Evident că cele 4 seturi de regiştri generali deţin conţinuturi identice în orice moment. Deci, prin multiplicarea resurselor hardware s-a creat posibilitatea execuţiei mai multor operaţii (instrucţiuni) fără a avea conflicte la resurse. O altă situaţie de acest fel, după cum deja am mai arătat, poate consta în accesul simultan la memorie a 2 procese distincte: unul de aducere a instrucţiunii (IF), iar celălalt de aducere a operandului sau scriere a rezultatului în cazul unei instrucţiuni LOAD / STORE (nivelul MEM). După cum am mai arătat, această situaţie se rezolvă în general printr-o arhitectură Harvard a busurilor şi cache-urilor. Totuşi, există microprocesoare care deţin busuri şi cache-uri unificate pe instrucţiuni şi date (Power PC 601, de exemplu).

86 Procesoare pipeline scalare cu set optimizat de instrucţiuni 90 Figura Structură de procesare multiplă. Să considerăm acum, fără a reduce din generalitate, o structură pipeline cu 5 nivele având timpul de"setup" de 7 cicli, descrisă în funcţionare de tabelul 3.3. Ciclu/ T1 T2 T3 T4 T5 T6 T7 Nivel N1 X N2 X X N3 X X N4 X X N5 X Tabelul 3.3. Descrierea funcţionării unei structuri pipeline cu 5 nivele Un X în tabel semnifică faptul că în ciclul Ti nivelul Nj este activ adică procesează informaţii. Să mai considerăm că această structură pipeline corespunde unui anumit proces (de ex. procesarea unei instrucţiuni). Se observă că un alt proces de acest tip, nu poate starta în ciclul următor (T2) datorită coliziunilor care ar putea să apară între cele două procese pe nivelul (N2, T3) şi respectiv (N3, T4). Mai mult, următorul proces n-ar putea starta

87 Procesoare pipeline scalare cu set optimizat de instrucţiuni 91 nici măcar în T3 din motive similare de coliziune cu procesul anterior în nivelul (N4, T5). În schimb procesul următor ar putea starta în T4 fără a produce coliziuni sau hazarduri structurale cum le-am denumit, deci la 2 cicli după startarea procesului curent. Se defineşte vectorul de coliziune al unei structuri pipeline având timpul de setup de (N+1) cicli, un vector binar pe N biţi astfel: dacă bitul i, i {0, 1,..., N-1} e 1 logic atunci procesul următor nu poate fi startat după i cicli de la startarea procesului curent, iar dacă bitul i este 0 logic, atunci procesul următor poate fi startat după i cicli fără a produce coliziuni cu procesul curent. Se observă de exemplu pentru structura pipeline anterioară că vectorul de coliziune este , însemnând deci că procesul următor nu trebuie startat în momentele T2 sau T3, în schimb poate fi startat fără probleme oricând după aceea. Se pune problema: cum trebuie gestionată o structură pipeline dată, caracterizată printr-un anumit vector de coliziune, asftel încât să se obţină o rată de procesare (procese / ciclu) maximă? Considerând o structură pipeline cu timpul de "setup" de 8 cicli şi având vectorul de coliziune ar trebui procedat ca în figurile următoare (figurile 3.16, 3.17): Figura 3.16 Principiul de lansare procese într-o structură pipe cu hazarduri structurale

88 Procesoare pipeline scalare cu set optimizat de instrucţiuni 92 Figura Graful de optimizare într-o structură pipeline Vectorul unei stări Sj, se obţine după relaţia: Vj = (VC) V (Vi * (m)), (3.4) V = SAU logic VC = vector coliziune Vi * (m) = vectorul Vi deplasat logic la stânga cu (m) poziţii binare Figura Trecerea dintr-o stare în alta Pentru maximizarea performanţei, se pune problema ca pornind din starea iniţială a grafului, să se determine un drum închis în graf cu proprietatea ca NS / L să fie maxim, unde NS = numărul de stări al drumului iar L = lungimea drumului. În cazul anterior considerat, avem L = = 13, iar NS = 4. Printr-o astfel de gestionare a structurii se evită coliziunile şi se obţine o performanţă optimă de 4 procese în 13 cicli, adică 0.31 procese / ciclu. De menţionat că o structură convenţională ar procesa doar procese / ciclu. Nu întotdeauna startarea procesului următor imediat ce acest lucru devine posibil ("greedy strategy"), duce la o

89 Procesoare pipeline scalare cu set optimizat de instrucţiuni 93 performanţă maximă. Un exemplu în acest sens ar fi o structură pipeline cu vectorul de coliziune asociat E adevărat însă că o asemenea strategie conduce la dezvoltarea unui algoritm mai simplu. Este clar că performanţa maximă a unei structuri pipeline se obţine numai în ipoteza alimentării ritmice cu date de intrare. În caz contrar, gestiunea structurii se va face pe un drum diferit de cel optim în graful vectorilor de coliziune. Pe baza unei tehnici elementare atribuită lui Patel şi Davidson (1976), se arată că prin modificarea tabelei aferentă structurii pipeline în sensul introducerii unor întârzieri, se poate îmbunătăţi performanţa benzii. Să considerăm acum o structură pipeline bifuncţională capabilă să execute 2 tipuri de procese: P1 şi respectiv P2. Aceste procese sunt descrise prin tabele adecvate, în care se arată ce nivele solicită procesul în fiecare ciclu. Este clar că aceste procese vor fi mai dificil de controlat. Pentru controlul acestora prin structură, este necesar a fi determinaţi mai întâi vectorii de coliziune şi anume: VC(P1, P1), VC(P1, P2), VC(P2, P1) şi VC(P2, P2), unde prin VC(Pi, Pj) am notat vectorul de coliziune între procesul curent Pi şi procesul următor Pj. Odată determinaţi aceşti vectori în baza tabelelor de descriere aferente celor două procese controlul structurii s- ar putea face prin schema de principiu din figura Figura Controlul unei structuri pipeline bifuncţionale Iniţial registrul "P1 control" conţine VC(P1, P1), iar registrul "P2 control" conţine VC(P2, P2). Procesul următor care se doreşte a fi startat în structură va face o cerere de startare către unitatea de control. Cererea va fi

90 Procesoare pipeline scalare cu set optimizat de instrucţiuni 94 acceptată sau respinsă după cum bitul cel mai semnificativ al registrului de control este 0 sau 1 respectiv. După fiecare iteraţie, registrul de control se va deplasa logic cu o poziţie la stânga după care se execută un SAU logic între conţinutul registrului de control, căile (A) şi (B) respectic căile de date (C) şi (D), cu înscrierea rezultatului în registrul de control. Se observă în acest caz că gestionarea proceselor se face după o strategie de tip "greedy" HAZARDURI DE DATE: DEFINIRE, CLASIFICARE, SOLUŢII DE EVITARE A EFECTELOR DEFAVORABILE Apar când o instrucţiune depinde de rezultatele unei instrucţiuni anterioare în bandă. Pot fi la rândul lor clasificate în 3 categorii, dependent de ordinea acceselor de citire respectiv scriere, în cadrul instrucţiunilor. Considerând instrucţiunile i şi j succesive, hazardul RAW (Read After Write) apare atunci când instrucţiunea j încearcă să citească o sursă înainte ca instrucţiunea i să scrie în aceasta. Apare deosebit de frecvent în implementările actuale de procesoare pipeline. Să considerăm secvenţa de instrucţiuni de mai jos procesată într-o structură pe 5 nivele, ca în figura următoare. Se observă că data ce urmează a fi incărcată în R5 este disponibilă doar la finele nivelului MEM aferent instrucţiunii I1, prea târziu pentru procesarea corectă a instrucţiunii I2 care ar avea nevoie de această dată cel târziu la începutul nivelului său ALU. Aşadar, pentru o procesare corectă, I2 trebuie stagnată cu un ciclu maşină. Figura Hazard RAW în cazul unei instrucţiuni LOAD Aceasta se poate realiza prin software, de exemplu prin inserarea unei instrucţiuni NOP între I1 şi I2 (umplerea "load delay slot"-ului - LDS) sau o altă instrucţiune utilă independentă de instrucţiunea I1. O altă modalitate de rezolvare constă în stagnarea hardware a instrucţiunii I2, stagnare

91 Procesoare pipeline scalare cu set optimizat de instrucţiuni 95 determinată de detecţia hazardului RAW de către unitatea de control. Realizarea întârzierii hardware se poate baza pe tehnica "scoreboarding" propusă pentru prima dată de către Seymour Cray ( CDC 6600). Se impune ca fiecare registru al procesorului din setul de regiştri să aibă un "bit de scor" asociat. Dacă bitul este zero, registrul respectiv e disponibil, dacă bitul este 1, registrul respectiv este ocupat. Dacă pe un anumit nivel al procesării este necesar accesul la un anumit registru având bitul de scor asociat pe 1, respectivul nivel va fi întârziat, permiţându-i-se accesul doar când bitul respectiv a fost şters de către procesul care l-a setat (figura 3.21a, figura 3.21.b). De remarcat că ambele soluţii bazate pe stagnarea fluxului (software - NOP sau hardware - semafoare) au acelaşi efect defavorabil asupra performanţei. Figura 3.21a. Detecţie hazard pe baza bitului de scor Figura 3.21b. Restartarea procesării instrucţiunilor Există situaţii în care hazardul RAW se rezolvă prin hardware fără să cauzeze stagnări ale fluxului de procesare ca în cazul anterior. Aceste tehnici de rezolvare se numesc tehnici forwarding (bypassing) bazate pe "pasarea anticipată" a rezultatului instrucţiunii i, nivelului de procesare aferent instrucţiunii j care are nevoie de acest rezultat. De exemplu să considerăm secvenţa:

92 Procesoare pipeline scalare cu set optimizat de instrucţiuni 96 ADD R1, R2, R3 ; R1 < ( R2 ) + ( R3 ) SUB R4, R1, R5 ; R4 < ( R1 ) - ( R5 ) Figura Implementarea "forwarding"-ului Rezultatul ALU aferent primei instrucţii (R2 + R3) este memorat în tampoanele ALU la finele fazei ALU a instrucţiunii ADD. Dacă unitatea de control va detecta hazardul RAW, va selecta pe parcursul fazei ALU aferente instrucţiunii SUB la intrarea A a ALU, tamponul care conţine (R2) + (R3) (în urma fazei ALU a instrucţiunii ADD), evitând astfel hazardul RAW. Desigur, este necesară implementarea proceselor de forwarding nu numai de la ieşirile ALU spre intrări ci şi din cadrul nivelelor următoare (de ex. nivelul MEM) spre intrările ALU. Această situaţie corespunde unor instrucţiuni dependente RAW dar nesuccesive strict în program. Valoarea "pasată" uneia din intrările ALU în acest caz, reprezintă rezultatul ALU memorat în nivelul următor (MEM) în cazul unor instrucţiuni aritmeticologice sau data citită din memoria cache de date în cazul unor instrucţiuni

93 Procesoare pipeline scalare cu set optimizat de instrucţiuni 97 LOAD. În implementarea controlului mecanismelor de forwarding, pot apare şi situaţii conflictuale care trebuiesc rezolvate pe bază de arbitrareprioritizare. Ca exemplu în acest sens se consideră secvenţa de instrucţiuni: I1: SUB R2,R1,R3 I2: AND R2,R2,R5 I3: ADD R6,R2,R4 În acest caz se observă imediat că apar necesare două "pasări anticipate" de valori: de la I1 la I3 (R2) pe intrarea A a ALU şi respectiv de la I2 la I3 (R2) pe aceeaşi intrare A a ALU. Este evident că în acest caz trebuie acordată prioritate nivelului pipeline mai "apropiat" de ALU, deci informaţiei produsă de ieşirile ALU şi nu celei situate în nivelul următor (MEM aici). Cu alte cuvinte, se preia pe intrarea A a ALU rezultatul produs de I2 şi nu cel produs de I1. Rezultă deci că şi astfel de potenţiale situaţii conflictuale trebuie implementate în logica de control a mecanismelor de forwarding. Hazardul WAR (Write After Read) poate să apară atunci când instrucţiunea j scrie o destinaţie înainte ca aceasta să fie citită pe post de sursă de către o instrucţiune anterioară notată i. Poate să apară când într-o structură pipeline există o fază de citire posterioară unei faze de scriere. De exemplu, modurile de adresare indirectă cu predecrementare pot introduce acest hazard, de aceea ele nici nu sunt implementate în arhitecturile de tip RISC. Figura Apariţia unui hazard WAR De precizat că aceste hazarduri WAR (Write After Read), pot apare şi datorită execuţiei instrucţiunilor în afara ordinii lor normale, din program (execuţie Out of Order), după cum se va remarca în continuare. Această procesare Out of Order este impusă de creşterea performanţei si se poate realiza atât prin mijloace hardware cât şi software, legat de optimizarea programelor pe arhitecturile pipeline. Hazardul WAW (Write After Write), apare atunci când instrucţiunea j scrie un operand înainte ca acesta să fie scris de către instrucţiunea i. Aşadar, în acest caz scrierile s-ar face într-o ordine eronată. Hazardul WAW

94 Procesoare pipeline scalare cu set optimizat de instrucţiuni 98 poate apărea în structurile care au mai multe nivele de scriere sau care permit unei instrucţiuni să fie procesată chiar dacă o instrucţiune anterioară este blocată. Modurile de adresare indirectă cu postincrementare pot introduce acest hazard, fapt pentru care ele sunt evitate în procesoarele RISC. De asemenea, acest hazard poate să apară in cazul execuţiei Out of Order a instrucţiunilor care au aceeaşi destinaţie. Figura 3.24 Apariţia unui unui hazard WAW Hazardurile de tip WAW sau WAR nu reprezintă hazarduri reale, ci mai degrabă conflicte de nume. Ele pot fi eliminate de către compilator (scheduler) prin redenumirea resurselor utilizate de program. De aceea se mai numesc dependenţe de ieşire respectiv antidependenţe. Ex.: I1: MULF Ri, Rj, Rk; Ri <--- ( Rj ) * ( Rk ) I2: ADD Rj, Rp, Rm; Rj <--- ( Rp) + ( Rm ) În acest caz poate să apară hazard WAR întrucât instrucţiunea I1 fiind o instrucţiune de coprocesor flotant se va încheia în execuţie după I2 care este o instrucţiune de procesor cu operanzi întregi. Am presupus deci că numărul de nivele aferent structurii pipeline a coprocesorului este mai mare decât numărul de nivele aferent procesorului. Rezultă deci că instrucţiunile I1, I2 se termină "Out of Order" (I2 înaintea lui I1). Secvenţa reorganizată prin software, care elimină hazardul WAR este : MULF Ri, Rj, Rk ADD Rx, Rp, Rm..... MOV Rj, Rx : Rj <- Rx (după Ri <- (Rj) x (Rk)) Prezentăm în continuare un exemplu de reorganizare a unui program în vederea eliminării hazardurilor de date şi a procesării sale optimale: I0 ADD R3, R1, R2 I1 LD R9, A(R7) I2 ADD R4, R3, R2 I3 ADD R5, R4, R6

95 Procesoare pipeline scalare cu set optimizat de instrucţiuni 99 I4 LD R4, A(R6) I5 LD R2, A(R4) Graful dependenţelor de date corespunzător acestei secvenţe este următorul (vezi figura 3.25): Figura Graful dependenţelor de date asociat secvenţei Aparent, pe baza grafului de mai sus, secvenţa reorganizată ar starta astfel: I0 ADD R3, R1, R2 I1 LD R5, A(R7) I4 LD R4, A(R6) I2 ADD R4, R3, R2 I3 ADD R5,R4,R6, etc. Se observă în acest caz că execuţia Out of Order a instrucţiunilor I4 şi I2 determină o procesare eronată a programului prin hazardul de tip WAW prin registrul R4. De asemenea, între instrucţiunile I3 şi I4 există hazard WAR prin acelaşi registru. Aşadar detecţia hazardului WAW între instrucţiunile I2 şi I4 determină impunerea unei relaţii de precedenţă între aceste instrucţiuni, adică procesarea lor trebuie să se realizeze în ordinea din program (In Order). În cazul nostru, este necesar deci ca I3, dependentă RAW de I2, să se execute înaintea instrucţiunii I4. Aceste restricţii au fost evidenţiate prin linie punctată în graful dependenţelor de date, anterior prezentat. Ţinând cont de cele de mai sus, pe baza grafului dependenţelor de date, secvenţa reorganizată corect va fi: I0 ADD R3, R1, R2 I1 LD R9, A(R7) I2 ADD R4, R3, R2 I3 ADD R5, R4, R6 I4 LD R4, A(R6) NOP; Compensare LDS! I5 LD R2, A(R4) Rata de procesare în acest caz este de 6/7 instr./tact, performanţă

96 Procesoare pipeline scalare cu set optimizat de instrucţiuni 100 superioară programului iniţial întrucât prin procesarea Out of Order, se evită la maximum dependenţele de date între instrucţiuni. Hazardul WAR între I3 şi I4 prin registrul R4 ar putea fi eliminat prin redenumirea registrului R4 în instrucţiunea I4. De asemenea, relaţii suplimentare de precedenţă între instrucţiuni impun într-un mod analog hazardurile de tip WAR (în ex. nostru între I3 şi I4). După cum am mai arătat, hazardurile WAR şi WAW nu reprezintă conflicte reale, ci doar aşa-zise conflicte de nume, ele nefiind considerate dependenţe adevărate. Considerând un procesor cu mai mulţi regiştri fizici decât cei logici, precedenţele impuse de aceste hazarduri pot fi eliminate uşor prin redenumirea regiştrilor logici cu cei fizici (register renaming). Principiul constă în existenţa unei liste a regiştrilor activi, adică folosiţi momentan, şi o alta a celor liberi (adică a celor nefolosiţi momentan). Fiecare schimbare a conţinutului unui registru logic prin program, se va face asupra unui registru fizic disponibil în lista regiştrilor liberi şi care va fi trecut în lista regiştrilor activi. În acest caz secvenţa în discuţie s-ar transforma în următoarea: I0: ADD R3a, R1a, R2a I1: LD R9a, A(R7a) I2: ADD R4a, R3a, R2a I3: ADD R5a, R4a, R6a I4: LD R4b, A(R6a) I5: LD R2b, A(R4b) În acest caz în optimizare nu ar mai avea importanţă decât dependenţele RAW, celelalte fiind eliminate. În baza grafului dependenţelor de date procesarea optimală ar însemna în acest caz: I0, I1, I4, I2, I3, I5, etc. Să observăm că deocamdată am prezentat exclusiv problema reorganizării aşa numitelor "basic-block"-uri sau unităţi secvenţiale de program. Se numeşte basic-block o secvenţă de instrucţiuni cuprinsă între două instrucţiuni de ramificaţie, care nu conţine nici o instrucţiune de ramificaţie şi care nu conţine nici o instrucţiune destinaţie a unei instrucţiuni de ramificaţie. Optimizarea programelor în basic - block-uri este rezolvată încă din perioada de pionierat a cercetărilor legate de microprogramare. Din păcate, prin concatenarea mai multor basic- block-uri optimizate nu se obţine un program optimizat. Se pune deci problema unei optimizări globale, a întregului program (vom reveni în capitolul următor).

97 Procesoare pipeline scalare cu set optimizat de instrucţiuni HAZARDURI DE RAMIFICAŢIE (HR): PROBLEME IMPLICATE ŞI SOLUŢII Pot fi generate de către instrucţiunile de ramificaţie (branch). Cauzează pierderi de perfomanţă în general mai importante decât hazardurile structurale şi de date. Efectele defavorabile ale instrucţiunilor de ramificaţie pot fi reduse prin metode soft (reorganizarea programului sursă), sau prin metode hard care determină în avans dacă saltul se va face sau nu (branch prediction) şi calculează în avans noul PC (program counter). Diverse statistici arată că instrucţiunile de salt necondiţionat au o frecvenţă între 2-8% din instrucţiunile unui program de uz general, iar cele de salt condiţionat între 11-17%. S-a arătat că salturile condiţionate simple se fac cu o probabilitate de cca. 50%, loop-urile cu o probabilitate de cca. 90%, iar majoritatea salturilor orientate pe bit nu se fac. Considerând o structură pipeline pe 5 nivele şi că la finele nivelului RD adresa de salt este disponibilă, efectul defavorabil al unei instrucţiuni de salt este sugerat în figura Evident că în alte structuri "branch delay slot"-ul (BDS) poate fi mai mare decât un singur ciclu. Figura Hazardul de ramificaţie pe un procesor scalar O primă soluţie pentru o procesare corectă, ar fi aceea de a dezvolta unitatea de control hardware în vederea detectării prezenţei saltului şi de a întârzia procesarea instrucţiunilor următoare cu un număr de cicli egal cu latenţa BDS-ului, până când adresa de salt devine disponibilă. Soluţia implică desigur reducerea performanţelor. Acelaşi efect l-ar avea şi "umplerea" BDS-ului de către scheduler cu instrucţiuni NOP în vederea întârzierii necesare. În continuare se vor prezenta succint principiile şi tehnicile care stau la baza soluţionării prin software a ramificaţiilor de program. Acestea se

98 Procesoare pipeline scalare cu set optimizat de instrucţiuni 102 bazează pe reorganizarea secvenţei de instrucţiuni maşină, astfel încât efectul defavorabil al salturilor să fie eliminat. În continuare se va prezenta o astfel de strategie atribuită lui T. Gross şi J. Hennessy şi dezvoltată încă din perioada de pionierat a acestor cercetări (1982). Mai întâi se defineşte o instrucţiune de salt situată la adresa b spre o instrucţiune situată la adresa l, ca un salt întârziat de ordinul n, dacă instrucţiunile situate la locaţiile b, b + 1,..., b + n şi l sunt executate întotdeauna când saltul se face. O primă soluţie de optimizare ar fi aceea de mutare a instucţiunii de salt cu n instrucţiuni "în sus". Acest lucru e posibil doar atunci când nici una dintre precedentele n instrucţiuni nu afectează determinarea condiţiilor de salt. În general, se poate muta instrucţiunea de salt cu doar k instrucţiuni "în sus" unde k reprezintă numărul maxim de instrucţiuni anterioare care nu afectează condiţiile de salt, k (0, n]. Când acest lucru se întâmplă, se poate aplica succesiv o altă tehnică ce constă în duplicarea primelor (n - k) instrucţiuni plasate începând de la adresa destinaţie a saltului, imediat după instrucţiunea de salt şi modificarea corespunzătoare a adresei de salt la acea adresă care urmează imediat după cele (n - k) instrucţiuni "originale", ca în figura Figura Soluţionarea unui hazard de ramificaţie prin duplicarea instrucţiunilor În cazul în care saltul condiţionat nu se execută, este necesar ca nici una dintre cele (n - k) instrucţiuni adiţionale să nu afecteze execuţia următoarelor (l + n - k) instrucţiuni. Metoda se recomandă atunci cînd saltul se face predominant, ceea ce poate fi stabilit în urma colectării unor statistici obţinute după rulare (profilings). În acest caz se realizează un câştig de performanţă în schimb se suplimentează spaţiul de memorare al programului. De remarcat că aceste microprocesoare nu au în general registru de flaguri şi deci salturile condiţionate nu se fac pe baza acestor flaguri ci pe baza unei condiţii specificate explicit în opcode-ul instrucţiunii

99 Procesoare pipeline scalare cu set optimizat de instrucţiuni 103 de salt. În continuare se prezintă un exemplu concret de reorganizare în vederea eliminării efectului BDS- ului, considerând însă că BDS- ul instrucţiunii de salt este doar de 1 tact. a) Figura Soluţionarea optimă Strategia anterioară îmbunătăţeşte rata de execuţie întotdeauna, indiferent dacă saltul se face ori nu se face. Dacă această reorganizare nu e posibilă, se încearcă una dintre următoarele 2 variante ((b) sau (c)). b) Figura Soluţie utilă când saltul se face preponderent În acest caz, rata de execuţie creşte doar atunci cînd saltul condiţionat se face. Dacă saltul nu se face, trebuie ca instrucţiunea introdusă în BDS (SUB R4, R5, R6), să nu provoace execuţia eronată a ramurii de program respective. Din păcate un astfel de caz măreşte zona de cod oricum şi în plus necesită timp de execuţie sporit cu o instrucţiune adiţională în cazul în care saltul nu se face.

100 Procesoare pipeline scalare cu set optimizat de instrucţiuni 104 c) Figura Soluţie utilă când saltul nu se face preponderent Acest ultim caz, creşte performanţa doar atunci când saltul condiţionat nu se face. Şi aici este necesar ca instrucţiunea introdusă în BDS, să nu provoace execuţia eronată a ramurii de program în cazul în care saltul se face. În concluzie, prin toate aceste strategii software se urmăreşte "umplerea" BDS-ului cu instrucţiuni utile şi care să nu afecteze programul din punct de vedere logic. În general microprocesoarele RISC, care deţin un BDS de una-două instrucţiuni, au posibilitatea - printr-un bit din codul instrucţiunii de salt condiţionat - să introducă stagnări hardware în cazul salturilor condiţionate sau să se bazeze pe umplerea BDS-ului cu instrucţiuni NOP sau cu alte instrucţiuni utile de către reorganizator (scheduler). În cele ce urmează, se vor prezenta pe larg, într-un mod critic şi pe deplin actualizat, cele mai performante strategii actuale de gestionare a ramificaţiilor de program şi anume predicţia prin hardware. Aceste strategii hardware de predicţie a branch-urilor au la bază un proces de predicţie "run - time" a ramurii de salt condiţionat precum şi determinarea în avans a noului PC. Ele sunt comune practic atât procesoarelor scalare cât şi celor cu execuţii multiple ale instrucţiunilor care se vor analiza în detaliu în capitolul următor al acestei lucrări. Cercetări recente insistă pe această problemă, întrucât s-ar elimina necesitatea reorganizărilor soft ale programului sursă şi deci s-ar obţine o independenţă faţă de maşină. Necesitatea predicţiei, mai ales în cazul procesoarelor cu execuţii multiple ale instrucţiunilor (VLIW, superscalare, etc., vezi cap. 3, 6) este imperios necesară. Notând cu BP (Branch Penalty) numărul mediu de cicli de aşteptare pentru fiecare instrucţiune din program, introduşi de salturile fals predicţionate, se poate scrie relaţia: BP= C (1-Ap) b IR (3.5) unde s-au notat prin:

101 Procesoare pipeline scalare cu set optimizat de instrucţiuni 105 C= Numărul de cicli de penalizare introduşi de un salt prost predicţionat Ap= Acurateţea predicţiei b= Procentajul instrucţiunilor de salt, din totalul instrucţiunilor, procesate în program IR= Rata medie de lansare în execuţie a instrucţiunilor Se observă că BP(Ap=0)=C b IR, iar BP(Ap=1)=0 (normal, predicţia este ideală aici). Impunând un BP=0.1 şi considerând valorile tipice: C=5, IR=4, b=22.5%, rezultă ca fiind necesară o acurateţe a predicţiei de peste 97.7%! Cu alte cuvinte, la o acurateţe de 97.7%, IR=4/1.4=2.8 instr./ciclu, faţă de IR=4 instr./ciclu, la o predicţie perfectă (Ap=100%). Este o dovadă clară că sunt necesare acurateţi ale predicţiilor foarte apropiate de 100% pentru a nu se "simţi" efectul defavorabil al ramificaţiilor de program asupra performanţei procesoarelor avansate. O metodă consacrată în acest sens o constituie metoda "branch prediction buffer" (BPB). BPB-ul reprezintă o mică memorie adresată cu cei mai puţin semnificativi biţi ai PC-ului aferent unei instrucţiuni de salt condiţionat. Cuvântul BPB este constituit în principiu dintr-un singur bit. Dacă acesta e 1 logic, atunci se prezice că saltul se va face, iar dacă e 0 logic, se prezice că saltul nu se va face. Evident că nu se poate şti în avans dacă predicţia este corectă. Oricum, structura va considera că predicţia este corectă şi va declanşa aducerea instrucţiunii următoare de pe ramura prezisă. Dacă predicţia se dovedeşte a fi fost falsă structura pipeline se evacuează şi se va iniţia procesarea celeilale ramuri de program. Totodată, valoarea bitului de predicţie din BPB se inversează. Figura O buclă tipică BPB cu un singur bit are un dezavantaj care se manifestă cu precădere în cazul buclelor de program ca cea din figura anterioară, în care saltul se va face ( N - 1) ori şi o dată, la ieşirea din buclă nu se face. Bazat pe tehnica

102 Procesoare pipeline scalare cu set optimizat de instrucţiuni 106 BPB în acest caz vom avea uzual 2 predicţii false: una la intrarea în buclă (prima parcurgere) şi alta la ieşirea din buclă (ultima parcurgere a buclei). Aşadar, acurateţea predicţiei va fi de (N - 2) * 100 / N %, iar saltul se face în proporţie de (N - 1) * 100 / N %. Pentru a elimina acest dezavantaj se utilizează 2 biţi de predicţie modificabili conform grafului de tranziţie de mai jos (numărător saturat). În acest caz acurateţea predicţiei unei bucle care se face de (N - 1) ori va fi (N - 1) * 100 / N %. Figura Automat de predicţie de tip numărător saturat pe 2 biţi Prin urmare, în cazul în care se prezice că branch-ul se va face, aducerea noii instrucţiuni se face de îndată ce conţinutul noului PC e cunoscut. În cazul unei predicţii incorecte, se evacuează structura pipeline şi se atacă cealaltă ramură a instrucţiunii de salt. Totodată, biţii de predicţie se modifică în conformitate cu graful din figură numit şi numărător saturat (vezi figura 3.32). Probabilitatea p ca predicţia să fie corectă pentru o instrucţiune de salt, este dată de relaţia: p = p1 * p2 + (1-p2) * p3, (3.6) unde am notat prin: p1, p2 - probabilitatea ca predicţia adresată în BPB să fie corectă şi să se refere la respectiva instrucţiune de salt; (1-p2)*p3 - probabilitatea ca predicţia să fie corectă, deşi nu se referă la instrucţiunea în curs de aducere. (Există de ex. posibilitatea ca 2 instrucţiuni de branch distincte să aibă cei mai puţini semnificativi biţi ai PC-ului identici). Este evident că maximizarea probabilităţii P se obţine prin maximizarea probabilităţilor p1, p2 (p3 nu depinde de caracteristicile BPBului). Datorită faptului că predictorul propriu-zis este implementat prin automate finite de stare, mai mult sau mai puţin complexe, aceste scheme au un caracter dinamic, comportarea lor adaptându-se funcţie de istoria

103 Procesoare pipeline scalare cu set optimizat de instrucţiuni 107 saltului respectiv. Există şi scheme de predicţie numite statice, caracterizate prin faptul că predicţia saltului pentru o anumită istorie a sa este fixă, bazată în general pe studii statistice ale comportamentului salturilor. Astfel de exemplu un salt care anterioarele trei instanţe s-a făcut efectiv (taken) poate fi predicţionat în tabele că se va face. Desigur că cel puţin principial, o schemă dinamică de predicţie este superioară uneia statice datorită adaptabilităţii sale. O altă problemă delicată constă în faptul că deşi predicţia poate fi corectă, de multe ori adresa de salt (noul PC) nu este disponibilă în timp util, adică la finele fazei de aducere IF. Timpul necesar calculului noului PC are un efect defavorabil asupra ratei de procesare. Soluţia la această problemă este dată de metoda de predicţie numită "branch target buffer" (BTB). Un BTB este constituit dintr-un BPB care conţine pe lângă biţii de predicţie, noul PC de după instrucţiunea de salt condiţionat şi eventual alte informaţii. De exemplu, un cuvânt din BTB ar putea conţine şi instrucţiunea ţintă a saltului. Astfel ar creşte performanţa, nemaifiind necesar un ciclu de aducere a acestei instrucţiuni, dar în schimb ar creşte costurile de implementare. Diferenţa esenţială între memoriile BPB şi BTB constă în faptul că prima este o memorie operativă iar a 2-a poate fi asociativă, ca în figura următoare. Figura Structură de predicţie BTB asociativă La începutul fazei IF se declanşează o căutare asociativă în BTB după conţinutul PC-ului în curs de aducere. În cazul în care se obţine hit se obţine în avans PC-ul aferent instrucţiunii următoare. Mai precis, considerând o

104 Procesoare pipeline scalare cu set optimizat de instrucţiuni 108 structură pipeline pe 3 faze (IF, RD, EX) algoritmul de lucru cu BTB-ul este în principiu următorul: IF) Se trimite PC-ul instrucţiunii ce urmează a fi adusă spre memorie şi spre BTB. Dacă PC-ul trimis corespunde cu un PC din BTB (hit) se trece în pasul RD2, altfel în pasul RD1. RD1) Dacă instrucţiunea adusă e o instrucţiune de branch, se trece în pasul EX1, altfel se continuă procesarea normală. RD2) Se trimite PC-ul prezis din BTB spre memoria de instrucţiuni. În cazul în care condiţiile de salt sunt satisfăcute, se trece în pasul EX 3, altfel în pasul EX2. EX1) Se introduce PC-ul instrucţiunii de salt precum şi PC-ul prezis în BTB. De obicei această alocare se face în locaţia cea mai de demult neaccesată (Least Recently Used - LRU). EX2) Predicţia s-a dovedit eronată. Trebuie reluată faza IF de pe cealaltă ramură cu penalizările de rigoare datorate evacuării structurilor pipeline. EX3) Predicţia a fost corectă, însă numai dacă şi PC-ul predicţionat este într-adevăr corect, adică neschimbat. În acest caz, se continuă execuţia normală. În tabelul următor (tabelul 3.4) sunt rezumate avantajele şi dezavantajele tehnicii BTB, anterior descrise. Instr. în BTB? Predicţie Realitate Cicli penalizare Da Da Da 0(Ctt) Da Da Nu Ctn Da Nu Nu 0 Da Nu Da Cnt Nu - Da Ct Nu - Nu 0 Tabelul 3.4. Penalizarea într-o structură de predicţie tip BTB În baza celor anterior discutate, rezultă că numărul de cicli de penalizare CP este dat de următoarea relaţie: CP = PBTB (Ptn*Ctn +Pnt*Cnt) +(1-PBTB )*P*Ct (3.7) unde s-a notat: P BTB - probabilitatea ca instrucţiunea de salt să se afle în BTB; P tn - probabilitatea ca saltul să fie prezis că se face şi în realitate nu se va face;

105 Procesoare pipeline scalare cu set optimizat de instrucţiuni 109 P nt - probabilitatea ca saltul să fie prezis că nu se face şi în realitate se va face; P - probabilitatea ca respectiva instrucţiune de salt să se facă; Această relaţie, necesită amendamente serioase pentru a fi utilă şi exactă, după cum se va arăta într-o contribuţie ulterioară a acestei lucrări. În acest caz, rata de procesare a instrucţiunilor ar fi dată de relaţia: IR= 1/(1 + Pb*CP), [instr./tact], (3.8) unde Pb= probabilitatea ca instrucţiunea curentă sa fie una de ramificaţie. Un model matematic simplu al acestei tehnici pentru un BTB cu N biţi de memorare, legat de eficienţa schemei, se referă la maximizarea funcţiei: s F = P ex (i)[p(i)*p tt (i)*v(i) - (1 - P(i))* P tn ( i )*W(i)] (3.9) i=1 s astfel încât n( i ) N, i=1 unde : n( i ) - numărul de biţi din BTB alocat instrucţiunii de branch i; N - numărul total de biţi din BTB; S - numărul de instrucţiuni branch procesate în cadrul programului; Relativ la expresia funcţiei F avem următorii termeni: P ex ( i ) - probabilitatea ca branch-ul i să se execute în cadrul programului ; P( i ) - probabilitatea ca branch-ul i să se facă; P tt ( i ) - probabilitatea ca branch-ul i să fie prezis că se face şi întradevăr se va face; V( i ) - numărul de cicli economisiţi în cazul unei predicţii corecte a branch-ului i; W( i ) - numărul de cicli de penalizare în cazul unei predicţii incorecte a branch-ului i; Obs.1) P tt ( i ) = P tn ( i ) = 0, dacă branch-ul i nu se află în BTB. Obs.2) S-a considerat că BTB nu îmbunătăţeşte performanţa pentru o predicţie corectă de tipul "saltul nu se face" (P nn ( i ) = 0), întrucât în acest caz structura se comportă în mod implict la fel ca şi o structură fără BTB. De asemenea, pentru o predicţie incorectă a faptului că "saltul se face", am considerat costul acelaşi cu cel pe care l-am avea fără BTB; din acest motiv Pnt( i ) nu intră în expresia funcţiei. Obs.3) Un branch trebuie introdus în BTB, cu prima ocazie când el se va face. Un salt care ar fi prezis că nu se va face nu trebuie introdus în

106 Procesoare pipeline scalare cu set optimizat de instrucţiuni 110 BTB pentru că nu are potenţialul de a îmbunătăţi performanţa (nu intră în expresia funcţiei F). Din acest motiv, există strategii care atunci când trebuie evacuat un branch din BTB îl evacuează pe cel cu potenţialul de performanţă minim, care nu coincide neapărat cu cel mai puţin folosit. Astfel se construieşte câte o variabilă MPP (Minimum Performance Potential), implementată în hardware, asociată fiecărui cuvânt din BTB. Evacuarea din BTB se face pe baza MPP-ului minim. Acesta se calculează ca un produs între probabilitatea ca un branch din BTB să fie din nou accesat (LRU) şi respectiv probabilitatea ca saltul să se facă. Aceasta din urmă se obţine pe baza unei istorii a respectivului salt (taken / not taken). Minimizarea ambilor factori duce la minimizarea MPP-ului şi deci la evacuarea respectivului branch din BTB, pe motiv că potenţialul său de performanţă este minim. În literatură se arată că prin astfel de scheme se ajunge la predicţii corecte în cca. (80-90)% din cazuri. Există implementări de mare performanţă în care biţii de predicţie sunt gestionaţi şi funcţie de "istoria" respectivei instrucţiuni de salt, pe baze statistice (INTEL NEX GEN, TRON, etc). Prin asemenea implementări creşte probabilitatea de predicţie corectă a branch-ului. Microprocesorul Intel Pentium avea un predictor de ramificaţii bazat pe un BTB cu 256 de intrări. O problemă dificilă este determinată de instrucţiunile de tip RETURN întrucât o aceeaşi instrucţiune, poate avea adrese de revenire diferite, ceea ce va conduce în mod normal la predicţii eronate, pe motivul modificării adresei eronate în tabela de predicţii. Desigur, problema se pune atât în cazul schemelor de tip BTB cât şi a celor de tip corelat, ce vor fi prezentate în continuare. Soluţia de principiu, constă în implementarea în hardware a unor aşa zise "stack - frame"- uri diferite. Acestea vor fi nişte stive, care vor conţine perechi CALL/ RETURN cu toate informaţiile necesare asocierii lor corecte. Astfel, o instrucţiune CALL poate modifica dinamic în tabela de predicţii adresa de revenire pentru instrucţiunea RETURN corespunzătoare, evitându-se astfel situaţiile nedorite mai sus schiţate. În literatură, bazat pe testări laborioase, se arată că se obţin predicţii corecte în cca. 88% din cazuri folosind un bit de predicţie şi respectiv în cca.93% din cazuri folosind 16 biţi de predicţie. Acurateţea predicţiilor creşte asimptotic cu numărul biţilor de predicţie utilizaţi, adică practic cu "istoria predicţiei". Schema de predicţie pe 4 stări din figura 3.33 poate fi generalizată uşor la N = 2 k stări. Se poate arăta că există N 2N * 2 N (stări x ieşiri) automate distincte de predicţie cu N stări, deşi multe dintre acestea sunt triviale din punct de vedere al predictiilor salturilor. În bibliografie se

107 Procesoare pipeline scalare cu set optimizat de instrucţiuni 111 arată într-un mod elegant, pe bază teoretică şi de simulare, că schema din figura 3.32 este cvasioptimală în mulţimea acestor automate de predicţie. În acord cu literatura de specialitate, mărirea numărului N de stări al automatului de predicţie pe k biţi nu conduce la creşteri semnificative ale performanţei. După cum vom arăta în continuare, prin scheme de predicţie corelată a salturilor se pot obţine performanţe superioare. Schemele de predicţie anterior prezentate se bazau pe comportarea recentă a unei instrucţiuni de salt, de aici predicţionându-se comportarea viitoare a acelei instrucţiuni de salt. Este posibilă îmbunătăţirea acurateţii predicţiei dacă aceasta se va baza pe comportarea recentă a altor instrucţiuni de salt, întrucât frecvent aceste instrucţiuni pot avea o comportare corelată în cadrul programului. Schemele bazate pe această observaţie se numesc scheme de predicţie corelată şi au fost introduse pentru prima dată în 1992 în mod independent de către Yeh şi Patt şi respectiv de Pan. Să considerăm pentru o primă exemplificare a acestei idei o secvenţă de program C extrasă din benchmark-ul Eqntott din cadrul grupului de benchmark-uri SPECint '92: (b1) if (x = = 2) x = 0; (b2) if (y = = 2) y = 0; (b3) if (x! = y) { Se observă imediat că în acest caz dacă salturile b1 şi b2 nu se vor face atunci saltul b3 se va face în mod sigur (x = y = 0). Aşadar saltul b3 nu depinde de comportamentul său anterior ci de comportamentul anterior al salturilor b1 şi b2, fiind deci corelat cu acestea. Evident că în acest caz schemele de predicţie anterior prezentate nu vor da randament. Dacă două branch-uri sunt corelate, cunoscând comportarea primului se poate anticipa comportarea celui de al doilea, ca în exemplul de mai jos: if (cond1)... if (cond1 AND cond2) Se poate observa că funcţia condiţională a celui de al doilea salt este dependentă de cea a primului. Astfel, dacă prima ramificaţie nu se face atunci se va şti sigur ca nici cea de a doua nu se va face. Dacă însă prima ramificaţie se va face atunci cea de a doua va depinde exclusiv de valoarea logică a condiţiei "cond2". Aşadar în mod cert aceste două ramificaţii sunt corelate, chiar dacă comportarea celui de al doilea salt nu depinde exclusiv de comportarea primului. Să considerăm acum pentru analiză o secvenţă de program C simplificată împreună cu secvenţa obţinută în urma compilării (s-a presupus că variabila x este asignată registrului R1).

108 Procesoare pipeline scalare cu set optimizat de instrucţiuni 112 if (x = = 0) (b1) BNEZ R1, L1 x = 1; ADD R1, R0, #1 if (x = = 1) L1: SUB R3, R1, #1 (b2) BNEZ R3, L2 Se poate observa că dacă saltul condiţionat b1 nu se va face, atunci nici b2 nu se va face, cele 2 salturi fiind deci corelate. Vom particulariza secvenţa anterioară, considerând iteraţii succesive ale acesteia pe parcursul cărora x variază de exemplu între 0 şi 5. Un BPB clasic, iniţializat pe predicţie NU, având un singur bit de predicţie, s-ar comporta ca în tabelul 3.5. Aşadar o astfel de schemă ar predicţiona în acest caz, întotdeauna greşit! Modul de predicţionare al unui BPB clasic Tabelul 3.5. Să analizăm acum comportarea unui predictor corelat având un singur bit de corelaţie (se corelează deci doar cu instrucţiunea de salt anterior executată) şi un singur bit de predicţie. Acesta se mai numeşte şi predictor corelat de tip (1, 1). Acest predictor va avea 2 biţi de predicţie pentru fiecare instrucţiune de salt: primul bit predicţionează dacă instrucţiunea de salt actuală se va face sau nu, în cazul în care instrucţiunea anterior executată nu s-a făcut iar al doilea analog, în cazul în care instrucţiunea de salt anterior executată s-a făcut. Există deci următoarele 4 posibilităţi (tabelul 3.6). Biţi predicţie Predicţie dacă precedentul salt nu s-a făcut Predicţie dacă precedentul salt s-a făcut NU / NU NU NU NU / DA NU DA DA / NU DA NU DA / DA DA DA Tabelul 3.6. Semnificaţia biţilor de predicţie pentru o schemă corelată

109 Procesoare pipeline scalare cu set optimizat de instrucţiuni 113 Ca şi în cazul BPB-ului clasic cu un bit, în cazul unei predicţii care se dovedeşte a fi eronată bitul de predicţie indicat se va complementa. Comportarea predictorului (1,1) pe secvenţa anterioară de program este prezentată în continuare (s-a considerat că biţii de predicţie asociaţi salturilor b1 şi b2 sunt iniţializaţi pe NU / NU). Modul de predicţionare al unei scheme corelate Tabelul 3.7. După cum se observă în tabelul 3.7, singurele două predicţii incorecte sunt când x = 5 în prima iteraţie. În rest, predicţiile vor fi întotdeauna corecte, schema comportându-se deci foarte bine spre deosebire de schema BPB clasică. În cazul general, un predictor corelat de tip (m,n) utilizează comportarea precedentelor m instrucţiuni de salt executate, alegând deci o anumită predicţie de tip Da sau Nu din 2m posibile iar n reprezintă numărul biţilor utilizaţi în predicţia fiecărui salt. În cazul unei bucle, o înregistrare a istoriei saltului sub forma (m=9) conduce în mod cert la o predicţie corectă a saltului ('0', adică nu se va face pentru că după 8 iteraţii consecutive, în a noua iteraţie se va ieşi din buclă), ceea ce printr-un predictor clasic BTB e mai dificil de predicţionat după cum deja am arătat; de asemenea o comportare alternativă a unui salt este simplu de predicţionat printr-o schemă corelată, în schimb printr-o schemă clasică este foarte dificil. Aşadar schemele corelate sunt eficiente atunci când predicţia depinde şi de un anumit pattern al istoriei saltului de predicţionat, corelaţia fiind în acest caz particular cu istoria pe m biţi chiar a acelui salt şi nu cu istoria anterioarelor m salturi. Un alt avantaj al acestor scheme este dat de simplitatea implementării hardware, cu puţin mai complexă decât cea a unui BPB clasic. Aceasta se bazează pe simpla observaţie că "istoria" celor mai recent executate m salturi din program, poate fi memorată într-un registru binar de deplasare pe m ranguri (registru de predicţie). Aşadar adresarea cuvântului de predicţie format din n biţi şi situat într-o tabelă de predicţii, se poate face foarte

110 Procesoare pipeline scalare cu set optimizat de instrucţiuni 114 simplu prin concatenarea c.m.p.s. biţi ai PC-ului instrucţiunii de salt curente cu acest registru de deplasare în adresarea BPB-ului de predicţie. Ca şi în cazul BPB-ului clasic, un anumit cuvânt de predicţie poate corespunde la mai multe salturi. Există în implementare 2 nivele deci: un registru de predicţie al cărui conţinut concatenat cu PC- ul c.m.p.s. al instrucţiunii de salt pointează la un cuvânt din tabela de predicţii (aceasta conţine biţii de predicţie, adresa destinaţie, etc.). Yeh nu face concatenarea PC - registru de predicţie şi în consecinţă se obţin rezultate nesatisfăcătoare datorită interferenţei diverselor salturi la aceeaşi locaţie din tabela de predicţii, lucru constatat şi eliminat de noi prin simulări proprii după cum se va arăta într-un viitor capitol al acestei lucrări. Pan analizează calitativ şi cantitativ într-un mod foarte atent, rolul informaţiei de corelaţie, pe exemple concrete extrase din benchmark-urile SPECint '92. Se arată că bazat pe predictoare de tip numărătoare saturate pe 2 biţi, schemele corelate (5-8 biţi de corelaţie utilizaţi) ating acurateţi ale predicţiilor de până la 11% în plus faţă de cele clasice. De remarcat că un BPB clasic reprezintă un predictor de tip (0,n), unde n este numărul biţilor de predicţie utilizaţi. Numărul total de biţi utilizaţi în implementarea unui predictor corelat de tip (m,n) este: N = 2 m * n * NI, (3.10) unde NI reprezintă numărul de intrări al BPB-ului utilizat. Există citate în literatură mai multe implementări de scheme de predicţie a ramificaţiilor, prima implementare comercială a unei astfel de scheme făcându-se în microprocesorul Intel Pentium Pro. Astfel de exemplu, implementarea tipică a unui predictor corelat de tip GAg (Global History Register, Global Prediction History Table) este prezentată în figura Tabela de predicţii PHT (Prediction History Table) este adresată cu un index rezultat din concatenarea a două informaţii ortogonale: PClow (i biţi), semnificând gradul de localizare al saltului, respectiv registrul de predicţie (HR- History Register pe k biţi), semnificând "contextul" în care se situează saltul în program. De fapt, introducerea PClow în adresarea tabelei precum şi introducerea tag-urilor în PHT, aparţin autorului acestei lucrări. Ambele contribuţii s-au făcut cu scopul eliminării interferenţelor branchurilor în tabela de predicţie. Adresarea PHT exclusiv cu HR, ducea la serioase interferenţe (mai multe salturi puteau accesa aceelaşi automat de predicţie din PHT), cu influenţe evident defavorabile asupra performanţelor. Desigur, PHT poate avea diferite grade de asociativitate. Un cuvânt din această tabelă are un format similar cu cel al cuvântului dintr-un BTB. Se pare că se poate evita concatenarea HR şi PClow în adresarea PHT, cu rezultate foarte bune, printr-o funcţie de dispersie tip SAU EXCLUSIV între

111 Procesoare pipeline scalare cu set optimizat de instrucţiuni 115 acestea, care să adreseze tabela PHT. Aceasta are o influenţă benefică asupra capacităţii tabelei PHT. În scopul reducerii interferenţelor diverselor salturi în tabela de predicţii, se prezintă o schemă numită PAg- Per Address History Table, Global PHT, a cărei structură este oarecum asemănătoare cu cea a schemei GAg. Componenta HR*(k) a introdus-o autorul acestei lucrări, având semnificaţia componentei HR de la varianta GAg, adică un registru global care memorează comportarea ultimelor k salturi. Fără această componentă, cred că schema PAg şi-ar pierde din capacitatea de adaptare la contextul programului în sensul în care schema GAg o face. În opinia mea, Yeh şi Patt renunţă într-un mod curios şi greşit la informaţia de corelaţie globală (HRg) în trecerea de la schemele de tip GAg la cele de tip PAg, în favoarea exclusivă a informaţiei de corelaţie locală (HRl). În schimb, componenta HR din structura History Table, conţine "istoria locală" (taken/ not taken) a saltului curent, ce trebuie predicţionat. După cum se va arăta mai departe, performanţa schemei PAg este superioară celei obţinute printr-o schemă de tip GAg, cu tributul de rigoare plătit complexităţii hardware. Figura Structură de predicţie de tip GAg Următoarea schemă de predicţie (de tip PAg) predicţionează pe baza a 3 informaţii ortogonale, toate disponibile pe chiar timpul fazei IF: istoria HRg a anterioarelor salturi corelate (taken / not taken), istoria saltului curent HRl şi PC-ul acestui salt. Dacă adresarea tabelei PHT s-ar face în schema PAg cu HR concatenat cu PClow(i), atunci practic fiecare branch ar avea propria sa tabelă PHT, rezultând deci o schemă şi mai complexă numită

112 Procesoare pipeline scalare cu set optimizat de instrucţiuni 116 PAp (Per Address History Table, Per Address PHT), a cărei schemă de principiu este prezentată mai jos (figura 3.36). Complexitatea acestei scheme o face practic neimplementabilă în siliciu la ora actuală, fiind doar un model utilizat în cercetare. Figura Structură de predicţie de tip PAg Figura Structură de predicţie de tip PAp

113 Procesoare pipeline scalare cu set optimizat de instrucţiuni 117 Desigur, este posibil ca o parte dintre branch-urile memorate în registrul HR, să nu se afle în corelaţie cu branch-ul curent, ceea ce implică o serie de dezavantaje. În astfel de cazuri pattern-urile din HR pot pointa în mod inutil la intrări diferite în tabela de predicţii, fără beneficii asupra performanţei predicţiei, separându-se astfel situaţii care nu trebuiesc separate. Mai mult, aceste situaţii pot conduce la un timp de "umplere" a structurilor de predicţie mai îndelungat, cu implicaţii defavorabile asupra performanţei. În opinia autorului, o critică valabilă pentru toate schemele corelate constă în faptul că informaţia de corelaţie globală (HRg) este insuficientă în predicţie. Mai precis, de exemplu în predicţia saltului curent notat b4, să considerăm că se dispune de conţinutul lui HRg = 101 şi respectiv HRl = 01. De asemenea să considerăm că cele 3 salturi anterioare celui curent şi a căror comportare (taken / not taken) este dată de conţinutul HRg (101 aici), au fost b1, b2 şi b3. Într-o următoare instanţă a apariţiei saltului b4 în exact acelaşi context al conţinuturilor HRg şi HRl ca cel precedent, se va apela acelaşi automat de predicţie accesat de anterioara apariţie a lui b4. Acest fapt poate fi total ineficient având în vedere că nu există nici o garanţie a faptului că şi de această dată, cele 3 salturi anterioare lui b4 au fost b1, b2 şi b3, exact ca în cazul precedent. Prin urmare HRg nu poate "prinde" întreg contextul de apariţie al unui anumit salt (b4 aici). Acest lucru l-am demonstrat pe bază de statistici în trace-urile benchmark-urilor Stanford, arătând că există salturi care în acelaşi context (HRg, HRl) au comportări aberante, adică de ex. în 56% din cazuri s-au făcut iar în 44% din cazuri, nu s-au făcut. Prin urmare aceste salturi sunt practic inpredictibile, din motivul că "acelaşi context" nu este în realitate acelaşi! Soluţia, în opinia mea, demonstrată de altfel la nivel de simulare software prin cercetări ale autorului şi colaboratorilor săi aflate în curs, ar consta în asocierea fiecărui bit din HRg cu PC-ul aferent saltului respectiv şi accesarea predicţiei pe baza acestei informaţii mai complexe. Astfel, am putea avea siguranţa că la contexte diferite de apariţie a unui anumit salt, se vor apela automate diferite de predicţie, asociate corect contextelor. Astfel s-ar reduce din efectele unui fenomen de interferenţă a predicţiilor încă nesesizat până acum. Compararea acestor noi scheme de predicţie trebuie făcută cu scheme clasice având aceeaşi complexitate structurală. Desigur, comprimarea acestui complex de informaţie (HRg cu PC-urile aferente) este posibilă şi poate chiar necesară, având în vedere necesitatea unor costuri rezonabile ale acestor scheme. Ea se poate realiza prin utilizarea unor funcţii de dispersie simple (de ex. tip SAU- EXCLUSIV). Oricum, această observaţie simplă poate conduce la îmbunătăţiri substanţiale ale acurateţii de predicţie, comparativ cu oricare dintre schemele actuale. Beneficiile unei asemenea

114 Procesoare pipeline scalare cu set optimizat de instrucţiuni 118 idei novatoare pot fi preliminate cantitativ prin determinarea în cadrul unui anumit trace a direcţiei (taken / not taken), pentru fiecare instanţă a unui anumit salt, apărut "în aceleaşi context" dat HRg, HRl. Procentaje (mult) diferite 100% pentru direcţia predilectă a saltului, nu vor arăta decât necesitatea implementării acestei idei, după cum am mai arătat. O altă cauză a unor comportamente "aberante" ale ramificaţiilor (comportamente diferite în contexte identice) poate fi cauzată de anumite pattern-uri mai "defavorabile" ale comportării respectivului salt. Astfel de ex., un "loop" care se face de 99 de ori şi o dată nu se face, este practic imposibil de a fi predicţionat corect 100% pe un context, normal, de genul HRg =111 respectiv HRl=11. De ce? Pur şi simplu pentru că nu se ştie dacă acel 111 conţinut în HRg este sau nu este cel de dinaintea "catastrofei" (a momentului în care se iese din buclă). Ce informaţii ar mai fi necesare atunci "prinderii" unor astfel de comportări imprevizibile. Fără îndoială acele PC-uri asociate fiecărui bit din HRg vor fi inutile în acest caz, în schimb ar putea fi utilă aici memorarea contorului de iteraţii undeva în tabelele de predicţie. Această ipoteză ar putea fi confirmată prin simulări specifice. O comparare echitabilă între schemele de predicţie clasice şi cele corelate trebuie să impună acelaşi număr de biţi utilizaţi în implementarea celor 2 scheme de comparat. Aşa de exemplu se compară un predictor (0,2) de capacitate 4k cu predictor (2,2) de capacitate 1k. Acurateţea predicţiilor schemei corelate este clar mai bună. Simulările s-au făcut pe procesorul DLX bazat pe 10 benchmark-uri SPECint 92. Schema corelată a obţinut predicţii corecte în 82%-100% din cazuri. Mai mult, predictorul (2,2) obţine rezultate superioare în comparaţie cu un BPB având un număr infinit de locaţii. Mai nou, având în vedere complexitatea tot mai mare a acestor predictoare, cu implicaţii defavorabile asupra timpului de căutare în structurile aferente, se vehiculează ideea unor predictoare hibride, constând în mai multe predictoare relativ simple asociate diferitelor tipuri de salturi în mod optimal. Aceste predictoare se activează în mod dinamic, funcţie de tipul saltului care este în curs de predicţionat. O alternativă ar fi ca să predicţioneze predictorul având cel mai mare grad de încredere, la momentul dat. Această soluţie pare a fi cea care ar putea depăşi performanţa complicatelor predictoare corelate pe 2 nivele. O problemă dificilă în predicţia branch-urilor o constituie salturile codificate în moduri de adresare indirecte, a căror acurateţe a predicţiei este deosebit de scăzută prin schemele anterior prezentate (cca.50%). Problema salturilor indirecte este de mare actualitate, cu precădere în contextul programelor obiectuale, legat mai ales de implementarea polimorfismelor.

115 Procesoare pipeline scalare cu set optimizat de instrucţiuni 119 Şi în filosofia programării procedurale apar apeluri idirecte (ex. apel indirect la funcţii). În acest caz, adresele de început ale diferitelor obiecte vizate sunt înscrise dinamic în registrul de indirectare al saltului care implementează polimorfismul. Practic, aici problema predicţiei direcţiei saltului este înlocuită cu una mult mai dificilă, anume cu aceea a predicţiei valorii adresei acestuia. Chang propune o structură de predicţie numită "target cache" special dedicată salturilor indirecte. În acest caz predicţia adresei de salt nu se mai face pe baza ultimei adrese ţintă a saltului indirect ca în schemele de predicţie clasice, ci pe baza alegerii uneia din ultimele adrese ţintă ale respectivului salt, memorate în structură. Aşadar, în acest caz structura de predicţie, memorează pe parcursul execuţiei programului pentru fiecare salt indirect ultimele N adrese ţintă. Predicţia se va face deci în acest caz pe baza următoarelor informaţii: PC-ul saltului, istoria acestuia, precum şi ultimele N adrese ţintă înregistrate. Structura de principiu a target cache-ului e prezentată în figura următoare, O linie din acest cache conţine ultimele N adrese ţintă ale saltului împreună cu tag-ul aferent. Figura Predicţia adresei în cazul salturilor indirecte Informaţia "istorie" provine din două surse: istoria saltului indirect sau a anterioarelor salturi şi respectiv ultimele N adrese ţintă, înscrise în linia corespunzătoare din cache. Aceste două surse de informaţie binară sunt prelucrate prin intermediul unei funcţii de dispersie (SAU EXCLUSIV), rezultând indexul de adresare în cache şi tag-ul aferent. După ce adresa ţintă a saltului devine efectiv cunoscută, se va introduce în linia corespunzătoare din cache. Schema acţionează "în mod disperat", mizând pe faptul că la

116 Procesoare pipeline scalare cu set optimizat de instrucţiuni 120 acelaşi context de apariţie a unui salt indirect se va asocia o aceeaşi adresă ţintă. Şi în opinia mea, această abordare principială pare singura posibilă în cazul acestor salturi greu predictibile. Prin astfel de scheme, măsurat pe benchmark-urile SPECint '95 acurateţea predicţiei salturilor indirecte creşte şi ca urmare, câştigul global asupra timpului de execuţie este de cca 4.3% - 9%. O altă idee nouă în predicţia branch-urilor, din păcate puţin mediatizată şi înţelesă în opinia mea, a fost lansată în 1996 de către Trevor Mudge şi constă în predicţia pe bază de lanţuri Markov utilizând algoritmul PPM (Prediction by Partial Matching), utilizat de altfel şi în procesarea (compresia) de imagini şi recunoaşterea vorbirii. Un predictor Markov de ordinul k predicţionează bitul următor pe baza celor k biţi precedenţi. În esenţă pentru predicţie, se caută patternul memorat în registrul HRg pe k biţi într-un şir binar mai lung al istoriei salturilor anterioare. Dacă acest pattern este găsit în şirul respectiv cel puţin o dată, predicţia se face corespunzător, pe baza unei statistici care determină de câte ori acest pattern a fost urmat în şir de 0 logic (non taken) şi respectiv de câte ori a fost urmat de 1 logic (taken). Dacă însă patternul din HRg nu a fost găsit în şirul de istorie, se construieşte un nou pattern mai scurt prin eludarea ultimului bit din HRg şi algoritmul se reia pe căutarea acestui nou pattern, ş.a.m.d. până la găsirea unui anumit pattern în şir. Se arată că deşi complexitatea implementării acestei noi scheme creşte de cca. 2 ori faţă de o schemă corelată, eficienţa sa - la acelaşi buget al implementării - este clar superioară. Nu sunt însă de acord cu autorii, care fără să o demonstreze, susţin că acest predictor reprezintă limita superioară a predictabilităţii ramificaţiilor. În capitolul 5 al acestei lucrări se va prezenta un concept total nou în predicţia ramificaţiilor, introdus de către autorul acestei lucrări, anume predictorul neuronal, bazat în cadrul procesului de predicţie pe reţele neuronale. În fine, o altă soluţie mai agresivă decât cele precedente, constă în aducerea instrucţiunilor din cadrul ambelor ramuri ale branch-ului în structuri pipeline paralele (multiple instructions streams). Când condiţia de salt e determinată, una din ramuri se va abandona. Totuşi, necesitatea predicţiei apare şi în acest caz datorită faptului că în anumite cazuri (salturi indirecte, reveniri din subrutine) adresa de salt este necunoscută la finele fazei IF şi deci ar trebui predicţionată în vederea procesării eficiente. Apoi, chiar cunoscute ambele adrese, apare dificultatea adresării memoriei şi aducerii blocurilor de instrucţiuni de la aceste 2 adrese distincte simultan din cache. Desigur că în acest caz sunt necesare redundanţe ale resurselor hard (cache-uri, unităţi de execuţie, busuri, logică de control, etc.) precum şi

117 Procesoare pipeline scalare cu set optimizat de instrucţiuni 121 complicaţii în logica de control. Dacă pe o ramură a programului există de exemplu o instrucţiune de tip STORE, procesarea acestei ramuri trebuie oprită întrucât există posibilitatea unei alterări ireparabile a unei locaţii de memorie. Această soluţie implică creşteri serioase ale costurilor, dar se pare că ar fi singura capabilă să se apropie oricât de mult faţă de idealul predicţiei absolut corecte. În cazul microprocesoarelor, aceste mecanisme de prefetch al ambelor ramuri, nu se aplică în prezent la microprocesoare, în principal datorită lărgimii de bandă limitate între microprocesor şi memorie. Tehnica s-a întâlnit în cazul supercomputerelor anilor '90 (ex. IBM-3033). Aceste tehnici de predicţie hardware a branch-urilor, datorită complexităţii lor, nu sunt implementate în mod uzual în microprocesoarele RISC scalare, întrucât se preferă tehnicile software de "umplere" a BDS-ului (limitat în general la o instrucţiune) cu instrucţiuni utile, în general anterioare celei de salt, lucru posibil în cca. 70%-80% din cazuri. În schimb, predicţia hardware este implementată în cazul unor procesoare superscalare, unde datorită BDS-ului de câteva instrucţiuni, umplerea lui cu instrucţiuni anterioare independente devine practic imposibilă PROBLEMA EXCEPŢIILOR ÎN PROCESOARELE RISC La sesizarea unui eveniment de excepţie se vor inhiba toate procesele de scriere, atât pentru instrucţiunea care a provocat excepţia, cât şi pentru următoarele aflate în bandă. Aceasta previne orice modificare a contextului procesorului care ar putea fi cauzată de continuarea procesării acestor instrucţiuni. În principiu, după terminarea instrucţiunii anterioare celei care a provocat excepţia, se intră în protocolul de tratare, în cadrul căruia se salvează intern sau extern PC-ul instrucţiunii care a provocat excepţia, precum şi contextul procesorului. În particular, în cazul în care instrucţiunea care a provocat excepţia se află într-un BDS de ordinul n şi saltul se face, atunci trebuie reluate cele n instrucţiuni BDS, precum şi instrucţiunea la care se face saltul. În acest caz trebuie salvate (n + 1) PC-uri pentru că în general adresele instrucţiunilor din BDS şi respectiv adresa instrucţiunii la care se face saltul nu sunt contigue. Dacă în cazul unei excepţii structura poate fi oprită astfel încât instrucţiunile anterioare celei care a provocat excepţia să poată fi complet executate şi respectiva instrucţiune împreună cu cele ulterioare ei să poată fi reluate în condiţii deterministe, se zice că avem o excepţie precisă. În caz contrar excepţia se zice imprecisă. Mai jos, se prezintă un exemplu de excepţie imprecisă :

118 Procesoare pipeline scalare cu set optimizat de instrucţiuni 122 DIVF F0, F2, F4 ADDF F6, F6, F8 SUBF F10, F10, F14 În acest caz instrucţiunile se vor termina Out of Order, adică ADDF şi SUBF se vor termina înaintea instrucţiunii DIVF. Să presupunem că instrucţiunea DIVF a determinat o derută aritmetică într-un moment în care ADDF şi SUBF s-au încheiat. Această situaţie implică o excepţie imprecisă, întrucât reluarea instrucţiunii DIVF se va face cu conţinutul regiştrilor F6 şi F10 alterat. Aceste situaţii sunt evident nedorite, iar dacă apar trebuie eliminate. Relativ la excepţiile imprecise, în literatură se precizează următoarele posibilităţi de soluţionare: a) Contextul CPU să fie dublat printr-un aşa-numit "history-file", care să păstreze toate resursele modelului de programare. În acest "historyfile" se înscriu noile rezultate la finele terminării "normale" (pur secvenţiale) a instrucţiunilor. În cazul apariţiei unei excepţii imprecise contextul procesorului se va încărca din acest context de rezervă (ex. CYBER 180 / 990). Există şi alte variaţiuni pe această idee. b) Prin această a 2-a soluţie de principiu, nu se permite terminarea unei instrucţiuni în bandă, până când toate instrucţiunile anterioare nu se vor fi terminat fără să cauzeze o excepţie. Astfel se garantează că dacă a apărut o excepţie în cadrul unei instrucţiuni, nici o instrucţiune ulterioară acesteia nu s-a încheiat şi totodată instrucţiunile anterioare ei s-au încheiat normal. Soluţia implică întârzieri ale procesării (ex. MIPS R 2000 / 3000). O altă problemă o constituie excepţiile simultane. Dacă luăm în considerare o procesare pe 5 nivele, în cadrul fiecărui nivel pot apare următoarele excepţii : IF - derută accesare pagină memorie, acces la un cuvânt nealiniat, etc. RD - cod ilegal de instrucţiune EX - diverse derute aritmetice (overflow) MEM - ca şi la IF WB - acces la resurse privilegiate în modul de lucru user. Rezultă imediat posibilitatea apariţiei simultane a 2 sau mai multe evenimente de excepţie. Să considerăm spre exemplificare secvenţa de instrucţiuni din figura 3.38, în cadrul căreia apar simultan două excepţii:

119 Procesoare pipeline scalare cu set optimizat de instrucţiuni 123 Figura Excepţie simultană Soluţia ar consta în tratarea prioritară a derutei instrucţiunii LOAD, după care se va relua această instrucţiune. Apoi va apare deruta de depăşire aferentă instrucţiunii ADD care va fi şi ea tratată. Figura Excepţii în ordine inversă Un caz mai dificil este acela în care excepţiile apar Out of Order ca în exemplul din figura În acest caz ar fi posibile 2 soluţii de principiu: 1) Să existe un flag de stare excepţie aferent fiecărei instrucţiuni şi care să fie testat la intrarea în nivelul WB. Dacă există setată vreo excepţie, se va trece în protocolul de tratare. Astfel se garantează că toate excepţiile din cadrul unei anumite instrucţiuni vor fi văzute înaintea excepţiilor apărute pe parcursul unei instrucţiuni următoare. 2) Se bazează pe tratarea excepţiei de îndată ce aceasta a apărut La sesizarea derutei din cadrul instrucţiunii (i + 1) se vor inhiba instrucţiunile (i - 2), (i - 1), i, (i + 1) şi prin protocolul de tratare se va relua instrucţiunea (i - 2). Apoi se va sesiza deruta din cadrul instrucţiunii i urmând ca după tratarea ei instrucţiunea i să se reia. Evident că deruta aferentă nivelului IF din cadrul instrucţiunii (i + 1) a fost anterior eliminată şi deci nu va mai apare. Menţionăm că majoritatea microprocesoarelor RISC deţin suficiente resurse hardware interne care să le permită în cazul apariţiei unei excepţii salvarea internă a contextului CPU. Evident că limitarea resurselor interne nu implică limitarea posibilităţii de imbricare a excepţiilor. Ca şi procesoarele CISC, procesoarele RISC deţin regiştri de stare excepţie, regiştri care conţin descrierea evenimentului de excepţie curent, regiştri care memorează adresa virtuală care a cauzat o excepţie, etc.

120 Procesoare pipeline scalare cu set optimizat de instrucţiuni AMBIGUITATEA REFERINŢELOR LA MEMORIE Dependenţele cauzate de variabilele aflate în memorie reprezintă o altă frână în calea obţinerii performanţei. Pentru exemplificare să considerăm secvenţa de program: ST 4 ( Ri ), R1 LD R2, 8 ( Rj ) După cum deja am arătat, există motive ca instrucţiunea LD să se execute înaintea instrucţiunii ST din motive de eficienţă a execuţiei (mascare latenţă, beneficii legate de procesarea Out of order, etc.). Acest lucru este posibil numai dacă cele 2 adrese de memorie sunt întotdeauna diferite. Este evident că dacă la un anumit moment ele sunt identice, semantica secvenţei se modifică inacceptabil. În general această problemă se rezolvă static, de către compilator, atunci când acest lucru e posibil. O componentă a acestuia ("disambiguating routine") compară cele 2 adrese de memorie şi returnează una dintre următoarele 3 posibilităţi: a) adrese întotdeauna distincte; b) adrese întotdeauna identice; c) cel puţin 2 adrese identice sau nu se poate determina. Aşadar, doar în primul caz putem fi siguri că execuţia anterioară a instrucţiunii LD faţă de instrucţiunea ST (sau simultană în cazul unui procesor MEM - Maşină cu Execuţie Multiplă, vezi capitolul 3) îmbunătăţeşte performanţa fără a cauza alterarea semantică a programului. Din păcate, nu se poate decide întotdeauna acest lucru în momentul compilării. Dezambiguizarea statică dă rezultate bune în cazul unor adresări liniare şi predictibile ale memoriei (de ex. accesări de tablouri, matrici, etc.). Ea presupune rezolvarea unor ecuaţii diofantice mai mult sau mai puţin complexe, similare cu cele necesare vectorizării buclelor de program. Prin urmare un reorganizator de program bazat pe dezambiguizarea statică va fi deosebit de conservativ în acţiunile sale. Dacă această comparare a adreselor de memorie se face pe parcursul procesarii programului prin hardware, se zice că avem o dezambiguizare dinamică. Aceasta este mai performantă decât cea statică dar necesită resurse hardware suplimentare şi deci costuri sporite. Pentru a pune în evidenţă performanţa superioară a variantei dinamice, să considerăm secvenţa:

121 Procesoare pipeline scalare cu set optimizat de instrucţiuni 125 for i = 1 to 100 do a[ 2i ]=... y = f(..., a[i+4],...) end Într-un singur caz din cele 100 posibile (i = 4), cele 2 referinţe la memorie a[2i] respectiv a[i + 4] sunt identice. Aşadar, o dezambiguizare statică va fi conservativă, nepermiţând optimizarea buclei deşi doar in 99% din cazuri acest lucru este posibil. Pentru rezolvarea situaţiei pe această cale este necesară scoaterea din buclă a dependenţelor de alias. O variantă dinamică însă, va putea exploata mai eficient acest fapt. Exemplu: for i=1 to 100 a[2]=x[1]; a[2i]=x[i]; y[1]=a[2]+5; y[i]=a[i+1]+5; for i=2 to 100 a[2i]=x[i]; y[i]=a[i+1]+5; ET: ET: ST Rj, a[2i]; // a[2i]=x[i] (x[i] este in Rj) LD Rk, a[i+1]; // y[i]=a[i+1] LD Rk, a[i+1]; // y[i]=a[i+1] NOP; //Load Delay Slot! ST Rj, a[2i]; // a[2i]=x[i]; //LDS full! ADD Rk, Rk, #5; // Rk=a[i+1]+5 ADD Rk, Rk, #5; // Rk=a[i+1]+5 ST Rk, y[i]; // y[i]=a[i+1]+5 ST Rk, y[i] LOOP ET LOOP ET Pe un procesor superscalar: ET: LD Rk, a[i+1]; // y[i]=a[i+1], ST Rj, a[2i]; // a[2i]=x[i]; LD/ST IN PARALEL! NOP; // LDS ADD Rk, Rk, #5; // Rk=a[i+1]+5 ST Rk, y[i]... LOOP ET Pe un procesor superscalar sau VLIW acest lucru este şi mai avantajos întrucât cele 2 operaţii din buclă se vor putea realiza simultan. Se consideră că progresele în această problemă pot duce la creşteri semnificative de performanţă în domeniul paralelismului la nivelul instrucţiunilor, după cum

122 Procesoare pipeline scalare cu set optimizat de instrucţiuni 126 vom demonstra şi noi într-o contribuţie ulterioară EXECUŢIA CONDIŢIONATĂ ŞI SPECULATIVĂ Execuţia condiţionată (predicativă) se referă la implementarea unor aşa numite instrucţiuni condiţionate. O instrucţiune condiţiontă se va executa dacă o variabilă de condiţie inclusă în corpul instrucţiunii îndeplineşte condiţia dorită. În caz contrar, instrucţiunea respectivă nu va avea nici un efect (NOP). Variabila de condiţie poate fi memorată într-un registru general al procesorului sau în regiştri special dedicaţi acestui scop numiţi regiştri booleeni. Astfel de exemplu, instrucţiunea CMOVZ R1, R2, R3 mută (R2) în R1 dacă (R3) = 0. Instrucţiunea TB5 FB3 ADD R1, R2, R3 execută adunarea numai dacă variabilele booleene B5 şi B3 sunt '1' respectiv '0'. În caz contrar, instrucţiunea este inefectivă. Desigur că variabilele booleene necesită biţi suplimentari în corpul instrucţiunii. Execuţia condiţionată a instrucţiunilor este deosebit de utilă în eliminarea salturilor condiţionate dintr-un program, simplificând programul şi transformând deci hazardurile de ramificaţie în hazarduri de date. Să considerăm spre exemplificare o construcţie if-then-else ca mai jos: if (R8<1) LT B6, R8, #1; if R8<1, B6<---1 R1 = R2 + R3, BF B6, Adr1; Dacă B6=0 salt la Adr1 else ADD R1, R2, R3 R1 = R5 - R7; BRA Adr2 ; salt la Adr2 R10 = R1 + R11; Adr1: SUB R1, R5, R7 Adr2: ADD R10, R1, R11 Prin rescrierea acestei secvenţe utilizând instrucţiuni condiţionate se elimină cele 2 instrucţiuni de ramificaţie obţinându-se următoarea secvenţă mai simplă şi mai eficientă de program: LT B6, R8, #1 TB6 ADD R1, R2, R3 FB6 SUB R1, R5, R7 ADD R10, R1, R11 Este clar că timpul de execuţie pentru această secvenţă este mai mic decât cel aferent secvenţei anterioare. Se arată că astfel de transformări reduc cu cca % instrucţiunile de salt condiţionat dintr-un program. Această execuţie condiţionată a instrucţiunilor facilitează execuţia speculativă. Codul situat după un salt condiţionat în program şi executat

123 Procesoare pipeline scalare cu set optimizat de instrucţiuni 127 înainte de stabilirea condiţiei şi adresei de salt cu ajutorul instrucţiunilor condiţionate, se numeşte cod cu execuţie speculativă, operaţia respectivă asupra codului numindu-se predicare. Predicarea reprezintă o tehnică de procesare care - utilizând instrucţiuni cu execuţie condiţionată - urmăreşte execuţia paralelă prin speculaţie a unor instrucţiuni şi reducerea numărului de ramificaţii din program, ambele benefice pt. minimizarea timpului de execuţie al programului. Acest mod de execuţie a instrucţiunilor poate fi deosebit de util în optimizarea execuţiei unui program. Prezentăm în continuare o secvenţă de cod iniţială şi care apoi e transformată de către scheduler în vederea optimizării execuţiei prin speculaţia unei instrucţiuni. SUB R1, R2, R3 SUB R1, R2, R3 LT B8, R1, #10 LT B8, R1, #10 BT B8, Adr FB8 ADDR7,R8,R1; speculativă ADD R7, R8, R1 BT B8, Adr SUB R10, R7, R4 SUB R10, R7, R4 Execuţia speculativă a instrucţiunii ADD putea fi realizată şi în lipsa variabilelor de gardă booleene dar atunci putea fi necesară redenumirea registrului R7 (dacă acesta ar fi în viaţă pe ramura pe care saltul se face). Orice instrucţiune - cu excepţia celor de tip STORE - poate fi executată speculativ. O posibilă strategie de a permite instrucţiuni STORE speculative constă în introducerea unui Data Write Buffer (DWB). Memorarea se va face întâi aici şi abia când condiţia de salt este cunoscută se va înscrie în memorie. Pe lângă avantajele legate de eliminarea salturilor, facilizarea execuţiei speculative, predicării, etc., execuţia condiţionată are şi câteva dezavantaje dintre care amintim: - instrucţiunile condiţionate anulate (NOP) necesită totuşi un timp de execuţie. În cazul speculaţiei, în aceste condiţii performanţa în execuţie scade. - dacă variabila de condiţie e evaluată târziu, utilitatea instrucţiunii condiţionate va fi micşorată. - promovarea unei instrucţiuni peste mai multe ramificaţii condiţionate în vederea execuţiei speculative necesită gardări multiple. - instrucţiunile condiţionate pot determina scăderea frecvenţei de tact a microprocesorului. Având în vedere cele de mai sus, utilitatea execuţiei condiţionate este încă discutată. MIPS, POWER-PC, SUN-SPARC, DEC ALPHA deţin doar o instrucţiune de tip MOVE condiţionată, în timp ce alte microarhitecturi precum HEWLET PACKARD PA, HARP, HSA, etc., permit execuţia

124 Procesoare pipeline scalare cu set optimizat de instrucţiuni 128 condiţionată a majorităţii instrucţiunilor maşină. La ora actuală există încă puţine evaluări cantitative care să stabilească avantajele/dezavantajele acestei idei într-un mod clar.

125 4. PROCESOARE CU EXECUŢII MULTIPLE ALE INSTRUCŢIUNILOR [7] 4.1. CONSIDERAŢII GENERALE. PROCESOARE SUPERSCALARE ŞI VLIW (EPIC) Un deziderat ambiţios este acela de se atinge rate medii de procesare de mai multe instrucţiuni per tact. Procesoarele care iniţiază execuţia mai multor operaţii simultan intr-un ciclu (sau tact) se numesc procesoare cu execuţii multiple ale instrucţiunilor. Un astfel de procesor aduce din cacheul de instrucţiuni una sau mai multe instrucţiuni simultan şi le distribuie spre execuţie în mod dinamic sau static (prin reorganizatorul de program), multiplelor unităţi de execuţie. Principiul acestor procesoare paralele numite şi "maşini cu execuţie multiplă" (MEM) constă în existenţa mai multor unităţi de execuţie paralele, care pot avea latenţe diferite. Pentru a facilita procesarea acestor instrucţiuni, acestea sunt codificate pe un singur cuvânt de 32 sau 64 de biţi uzual, pe modelul RISC anterior prezentat. Dacă decodificarea instrucţiunilor, detecţia dependenţelor de date dintre ele, rutarea şi lansarea lor în execuţie din bufferul de prefetch înspre unităţile funcţionale se fac prin hardware, aceste procesoare MEM se mai numesc şi superscalare. Pot exista mai multe unităţi funcţionale distincte, dedicate de exemplu diverselor tipuri de instrucţiuni tip întreg sau flotant. Aşadar execuţiile instrucţiunilor întregi, se suprapun cu execuţiile instrucţiunilor flotante (FP- Flotant Point). În cazul procesoarelor MEM, paralelismul temporal determinat de procesarea pipeline se suprapune cu un paralelism spaţial determinat de existenţa mai multor unităţi de execuţie. În general structura pipeline a coprocesorului are mai multe nivele decât structura pipeline a procesorului ceea ce implică probleme de sincronizare mai dificile decât în cazul procesoarelor pipeline scalare. Acelaşi lucru este valabil şi între diferite alte tipuri de instrucţiuni având latenţe de execuţie diferite. Caracteristic deci procesoarelor superscalare este faptul că dependenţele de date între instrucţiuni se rezolvă prin hardware, în momentul decodificării instrucţiunilor. Modelul ideal de procesare superscalară, în cazul unui

126 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 128 procesor care poate aduce şi decodifica 2 instrucţiuni simultan este prezentat în figura 4.1. Este evident că în cazul superscalar complexitatea logicii de control este mult mai ridicată decât în cazul pipeline scalar, întrucât detecţia şi sincronizările între structurile pipeline de execuţie cu latenţe diferite şi care lucrează în paralel devin mult mai dificile. De exemplu un procesor superscalar având posibilitatea aducerii şi execuţiei a "n" instrucţiuni maşină simultan, necesită n(n-1)/2 unităţi de detecţie a hazardurilor de date între aceste instrucţiuni (comparatoare digitale), ceea ce conduce la o complexitate ridicată a logicii de control. Figura 4.1. Modelul execuţiei superscalare S-ar putea deci considera aceste procesoare MEM ca fiind arhitecturi de tip MIMD (Multiple Instructions Multiple Data) în taxonomia lui Michael Flynn. De remarcat totuşi că în această categorie sunt introduse cu precădere sistemele multiprocesor care exploatează paralelismul la nivelul mai multor aplicaţii (coarse grain parallelism), arhitecturile RISC ca şi cele de tip MEM exploatând paralelismul instrucţiunilor la nivelul aceleiaşi aplicaţii (fine grain parallelism). Desigur că - din punctul de vedere al acestei taxonomii - arhitecturile pipeline scalare (RISC), ar fi încadrabile în clasa SISD (Single Instruction Single Data), fiind deci incluse în aceeaşi categorie cu procesoarele cele mai convenţionale (secvenţiale), ceea ce implică o slăbiciune a acestei sumare taxonomii. În figura 4.2 se prezintă o structură tipică de procesor superscalar care deţine practic 2 module ce lucrează în paralel: un procesor universal şi un procesor destinat operaţiilor în virgulă mobilă. Ambele module deţin unităţi de execuţie proprii având latenţe diferite. La anumite microprocesoare superscalare regiştrii CPU sunt diferiţi de regiştrii FP, pentru a se reduce hazardurile structurale (în schimb creşteri serioase ale costurilor şi dificultăţi tehnologice) iar la altele (de ex. Motorola 88100), regiştrii CPU sunt identici cu cei ai coprocesorului. De exemplu, pentru eliminarea hazardurilor

127 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 129 structurale, multe dintre aceste microprocesoare nu deţin "clasicul" registru al indicatorilor de condiţie. Salturile condiţionate se realizează prin compararea pe o anumită condiţie, a 2 dintre registrele codificate în instrucţiune. Hazardurile structurale la resursele hardware interne se elimină prin multiplicarea acestora şi sincronizarea adecvată a proceselor. Figura 4.2. Structură de procesor superscalar pipeline De remarcat că procesoarele superscalare, determină apropierea ratei de execuţie la una sau, în cazul în care se pot aduce mai multe instrucţiuni simultan, la mai multe instrucţiuni per ciclu. Dificultăţile de sincronizare sporite, se rezolvă prin utilizarea unor tehnici hardware bazate pe "scoreboarding" deosebit de sofisticate. Majoritatea microprocesoarelor RISC actuale sunt de tip superscalar (conţin cel puţin un coprocesor integrat în chip). Un procesor superscalar care aduce din cache-ul de instrucţiuni mai multe instrucţiuni primitive simultan, poate mări rata de procesare la instr./ciclu măsurat pe o mare diversitate de benchmark-uri, la nivelul realizărilor practice între anii Exemple remarcabile de microprocesoare superscalare comerciale de tip RISC, sunt: INTEL 960 CA, SUN SuperSPARC, MPC 601, 603, 620 (POWER PC), etc. Microprocesoarele Intel Pentium, AMD K6, etc., sunt practic procesoare având model de programare CISC dar execuţie hardware superscalară. Procesoarele VLIW (Very Long Instruction Word) reprezintă procesoare care se bazează pe aducerea în cadrul unei instrucţiuni multiple a mai multor instrucţiuni RISC independente pe care le distribuie spre procesare unităţilor de execuţie. Aşadar, rata de execuţie ideală la acest model, este de n instrucţiuni/ciclu. Pentru a face acest model viabil, sunt

128 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 130 necesare instrumente soft de exploatare a paralelismului programului, bazate pe gruparea instrucţiunilor simple independente şi deci executabile în paralel, în instrucţiuni multiple. Arhitecturile VLIW sunt tot de tip MEM. Principiul VLIW este sugerat în figura 4.3: Figura 4.3. Decodificarea şi alocarea instrucţiunilor într-un procesor VLIW În cadrul acestui model, se încearcă prin transformări ale programului, ca instrucţiunile RISC primitive din cadrul unei instrucţiuni multiple să fie independente şi deci să se evite hazardurile de date între ele, a căror gestionare ar fi deosebit de dificilă în acest caz. Performanţa procesoarelor VLIW este esenţial determinată de programele de compilare şi reorganizare care trebuie să fie deosebit de "inteligente". De aceea acest model de arhitectură se mai numeşte uneori şi EPIC (Explicitly Parallel Instruction Computing). Prin urmare, în cazul modelului de procesor VLIW, compilatorul trebuie să înglobeze mai multe instrucţiuni RISC primitive independente în cadrul unei instrucţiuni multiple, în timp ce în cazul modelului superscalar, rezolvarea dependenţelor între instrucţiuni se face prin hardware, începând cu momentul decodificării acestor instrucţiuni. De asemenea, poziţia instrucţiunilor primitive într-o instrucţiune multiplă determină alocarea acestor instrucţiuni primitive la unităţile de execuţie, spre deosebire de modelul superscalar unde alocarea se face dinamic prin control hardware. Acest model de procesor nu mai necesită sincronizări şi comunicaţii de date suplimentare între instrucţiunile primitive după momentul decodificării lor, fiind astfel mai simplu din punct de vedere hardware decât modelul superscalar. Un model sugestiv al principiului de procesare VLIW este prezentat în figura 4.4.

129 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 131 Figura 4.4. Principiul de procesare VLIW Pentru exemplificarea principiului de procesare MEM, să considerăm secvenţa de program de mai jos : LOOP: LD F0,0(R1) ADD F4,F0,F2 SD 0(R1),F4 SUB R1,R1,#8 BNEZ R1, LOOP Se va analiza în continuare cum ar trebui reorganizată şi procesată secvenţa de program anterioară pentru a fi executată pe un procesor VLIW care poate aduce maxim 5 instrucţiuni primitive simultan şi deţine 5 unităţi de execuţie distincte şi anume: 2 unităţi LOAD / STORE (MEM1, MEM2), 2 unităţi de coprocesor flotant (FPP1, FPP2) şi o unitate de procesare a instrucţiunilor întregi şi respectiv a branch-urilor. Tabelul 4.1. Execuţia instrucţiunilor pe un procesor VLIW cu 5 unităţi de execuţie specializate (corectati eventualele erori din program!) De remarcat în acest caz o rată medie de procesare de 2.4 instrucţiuni / ciclu. Altfel spus, bucla de program anterioară se execută în doar 1.42 cicli

130 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 132 (10 cicli / 7 bucle). De remarcat printre altele, o redenumire a regiştrilor absolut necesară acestei procesări agresive. Posibilităţile hard / soft aferente unei asemenea procesări vor fi prezentate succint în continuare. Este clar că performanţa procesoarelor MEM este esenţial determinată de programele de compilare şi reorganizare care trebuie să fie deosebit de "inteligente". Cercetări realizate în comun la Universitatea Stanford, USA şi firma DEC (Digital Equipment Corporation) pe procesoare VLIW cu 4 instrucţiuni simultane, au arătat că în aplicaţii reale se ajunge la execuţia a max 2-3 instrucţiuni / ciclu, prin compilatoare optimizate. Deşi rare, există realizări comerciale de computere VLIW cu software de optimizare de oarecare succes pe piaţă : IBM RS / 6000 ( 4 instrucţiuni / ciclu, teoretic), INTEL 860 (maxim 2 instrucţiuni / ciclu), APOLLO DN 10000, etc. Aceste realizări sunt disponibile comercial începând cu anul 1991, deşi cercetările au fost iniţiate începând din Firma Intel a anunţat că noul său model de procesor având numele de cod Merced (IA-64), ce va fi lansat în anii , va fi realizat pe principii VLIW (EPIC). Având în vedere că în cadrul acestor arhitecturi compilatorul este puternic senzitiv la orice modificare hardware, personal prevăd o legătură hardware - software mai pronunţată decât cea actuală (1998), începând cu lansarea comercială a acestei arhitecturi noi. Necesităţile de "upgrade" hardware - software, cred de asemenea vor fi mai imperioase prin această filosofie EPIC, necesitând deci mai mult decât până acum din partea utilizatorilor, serioase şi continue investiţii financiare corespunzător noilor modele. IA-64 (Intel Architecture) va fi prima arhitectură Intel pe 64 de biţi care va îngloba două caracteristici esenţiale descrise deja în capitolul 2: execuţia condiţionată prin variabile de gardă booleene a instrucţiunilor ( execuţie predicativă ) şi respectiv execuţia speculativă a instrucţiunilor cu beneficii asupra mascării latenţei unor instrucţiuni mari consumatoare de timp şi deci asupra vitezei de procesare. Arhitectura se bazează pe explicitarea paralelismului instrucţiunilor la nivelul compilatorului într-un mod similar cu cel din arhitecturile VLIW. Intel susţine că programele optimizate pe o anumită maşină IA-64 vor funcţiona fără probleme pe oricare altă viitoare maşină întrucât latenţele unităţilor de execuţie ca şi numărul acestora sunt invizibile pentru optimizatorul de cod. Aceasta se realizează însă prin interconectarea totală a unităţilor de execuţie care se sincronizează prin tehnici de tip scoreboarding. Rezultă deci că un program obiect portat de la o versiune mai veche de procesor la alta mai nouă, chiar dacă va funcţiona totuşi corect, se va procesa mai lent decât dacă ar fi optimizat special pentru noua variantă de procesor. Dificultăţile principale ale modelului VLIW sunt următoarele:

131 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore Paralelismul limitat al aplicaţiei, ceea ce determină ca unităţile de execuţie să nu fie ocupate permanent, fapt valabil de altfel şi la modelul superscalar. - Incompatibilitate software cu modele succesive şi compatibile de procesoare care nu pot avea în general un model VLIW identic datorită faptului că paralelismul la nivelul instrucţiunilor depinde de latenţele operaţiilor procesorului scalar, de numărul unităţilor funcţionale şi de alte caracteristici hardware ale acestuia. - Dificultăţi deosebite în reorganizarea aplicaţiei (scheduling) în vederea determinării unor instrucţiuni primitive independente sau cu un grad scăzut de dependenţe. - Creşterea complexităţii hardware şi a costurilor ca urmare a resurselor multiplicate, căilor de informaţie "lăţite", etc. - Creşterea necesităţilor de memorare ale programelor datorită reorganizărilor soft şi "împachetării" instrucţiunilor primitive în cadrul unor instrucţiuni multiple care necesită introducerea unor instrucţiuni NOP (atunci când nu există instrucţiuni de un anumit tip disponibile spre a fi asamblate într-o instrucţiune multiplă). În esenţă, prin aceste modele MEM se încearcă exploatarea paralelismului din programe secvenţiale prin excelenţă, de unde şi limitarea principală a acestui domeniu de "low level parallelism". Actualmente, datorită faptului că aceste procesoare sunt mult mai ieftine decât procesoarele vectoriale (superprocesoare), şi totodată foarte performante, se pune problema determinării unor clase largi de aplicaţii în care modele superscalar, superpipeline şi VLIW să se comporte mai bine sau comparabil cu modelul vectorial. Se poate arăta relativ simplu, că din punct de vedere teoretic performanţa unui procesor superscalar având N unităţi funcţionale, fiecare cu o structură pipeline pe M nivele, este echivalentă cu cea a unui procesor scalar superpipeline cu o structură pipeline pe M*N nivele. Asocierea unei arhitecturi optimale unei clase de aplicaţii dată, este o problemă dificilă. Performanţa procesoarelor scalare superpipeline, superscalare şi VLIW este în strânsă legătură cu progresele compilatoarelor specifice acestor structuri, compilatoare care trebuie să extragă cât mai mult din paralelismul existent la nivelul instrucţiunilor programului. De remarcat că modelele superscalar şi VLIW nu sunt exclusive, în implementările reale se întâlnesc adesea procesoare hibride, în încercarea de a se optimiza raportul performanţă preţ. După cum se va vedea, spre exemplu tehnicile soft de optimizare sunt comune ambelor variante de procesoare. Aceste modele arhitecturale de procesoare paralele sunt

132 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 134 considerate a face parte din punct de vedere arhitectural, din generaţia a IIIa de microprocesoare, adică cea a anilor MODELE DE PROCESARE ÎN ARHITECTURILE SUPERSCALARE În cazul procesoarelor superscalare sunt citate în literatura de specialitate 3 modalităţi distincte de procesare şi anume: In Order Issue In Order Completion (IN - IN), In Order Issue Out of Order Completion (IN - OUT) şi respectiv Out of Order Issue Out of Order Completion (OUT - OUT). Pentru exemplificarea afirmaţiei de mai sus, să considerăm o secvenţă de instrucţiuni I1 - I6 cu următoarele particularităţi: I1 necesită 2 cicli pentru execuţie, I3 şi I4 sunt în conflict structural, între I4 şi I5 există dependenţă RAW iar I5 şi I6 sunt de asemenea în conflict structural. În aceste condiţii şi considerând un procesor superscalar care poate aduce şi decodifica 2 instrucţiuni simultan şi care deţine 2 unităţi de execuţie, avem situaţiile următoare pe cele trei modele: a) Modelul IN - IN Este caracterizat prin faptul că procesorul nu decodifică următoarea pereche de instrucţiuni, decât în momentul în care perechea anterioară se execută. Aşadar atât execuţia cât şi înscrierea rezultatelor se face în ordinea din program ca în figură. Tabelul 4.2. Exemplu de procesare IN-IN b) Modelul IN - OUT Este caracterizat de faptul că execuţia propriu-zisă se face în ordine, în schimb înscrierea rezultatelor se face de îndată ce o instrucţiune s-a terminat

133 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 135 de executat. Modelul este mai eficient decât cel precedent însă poate crea probleme de genul întreruperilor imprecise care trebuiesc evitate prin tehnici deja amintite în capitolul 3. Tabelul 4.3. Exemplu de procesare IN-OUT c) Modelul OUT - OUT Este cel mai agresiv şi performant model de procesare a instrucţiunilor într-un procesor superscalar. Instrucţiunile sunt aduse şi decodificate sincron, presupunând deci existenţa unui buffer între nivelul de decodificare şi execuţie (instructions window). Astfel creşte capacitatea de anticipare a instrucţiunilor independente dintr-un program. Modelul permite o exploatare mai bună a paralelismului instrucţiunilor la nivelul unui program dat, prin creşterea probabilităţii de determinare a unor instrucţiuni independente, stocate în buffer. Exemplu de procesare OUT-OUT Tabelul 4.4. Desigur că execuţia Out of Order este posibilă numai atunci când dependenţele de date între instrucţiuni o permit. Cade în sarcina hardului

134 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 136 eliminarea dependenţelor şi alocarea instrucţiunilor din buffer la diversele unităţi de execuţie (rutarea) ARHITECTURA LUI R. TOMASULO A fost proiectată şi implementată pentru prima dată în cadrul unităţii de calcul în virgulă mobilă din cadrul sistemului IBM / 91 şi este atribuită lui Roberto Tomasulo, considerat a fi fost pionierul procesării superscalare şi pe acest motiv, laureat al prestigiosului premiu Eckert Mauchly Award pe anul 1996, acordat celor mai performanţi constructori şi proiectanţi de calculatoare. Arhitectura este una de tip superscalar având deci mai multe unităţi de execuţie, iar algoritmul de control al acestei structuri stabileşte relativ la o instrucţiune adusă, momentul în care aceasta poate fi lansată în execuţie şi respectiv unitatea de execuţie care va procesa instrucţiunea. Arhitectura permite execuţia multiplă şi Out of Order a instrucţiunilor şi constituie modelul de referinţă în reorganizarea dinamică a instrucţiunilor într-un procesor superscalar. De asemenea, algoritmul de gestiune aferent arhitecturii permite anularea hazardurilor WAR şi WAW printr-un ingenios mecanism hardware de redenumire a regiştrilor, fiind deci posibilă execuţia Out of Order a instrucţiunilor şi în aceste cazuri. Aşadar, singurele hazarduri care impun execuţia In Order sunt cele de tip RAW. În cadrul acestei arhitecturi, detecţia hazardurilor şi controlul execuţiei instrucţiunilor sunt distribuite iar rezultatele instrucţiunilor sunt "pasate anticipat" direct unităţilor de execuţie prin intermediul unei magistrale comune numită CDB (Common Data Bus). Arhitectura de principiu este prezentată în figura 4.5. Ea a fost implementată prima dată în unitatea de virgulă mobila FPP a calculatorului IBM 360/91, pe baza căreia se va prezenta în continuare. Staţiile de rezervare (SR) memorează din SIF (Stiva Instrucţiuni Flotante - pe post de buffer de prefetch aici) instrucţiunea ce urmează a fi lansată spre execuţie. Execuţia unei instrucţiuni începe dacă există o unitate de execuţie neocupată momentan şi dacă operanzii aferenţi sunt disponibili în SR aferentă. Fiecare unitate de execuţie (ADD, MUL) are asociată o SR proprie. Precizăm că unităţile ADD execută operaţii de adunare / scădere iar unitaţile MUL operaţii de înmulţire / împărţire. Modulele LB şi SB memorează datele încărcate din memoria de date respectiv datele care urmează a fi memorate. Toate rezultatele provenite de la unităţile de execuţie şi de la bufferul LB sunt trimise pe magistrala CDB.

135 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 137 Bufferele LB, SB precum şi SR deţin câmpuri de TAG necesare în controlul hazardurilor de date între instrucţiuni. Figura 4.5. Arhitectura lui Tomasulo Există în cadrul acestei unităţi de calcul în virgulă mobilă şi deci în cadrul mai general al procesării superscalare, 3 stagii de procesare a instrucţiunilor şi anume: 1) Startare - aducerea unei instrucţiuni din SIF (bufferul de prefetch) într-o staţie de rezervare. Aducerea se va face numai dacă există o SR disponibilă. Dacă operanzii aferenţi se află în FPR (setul de regiştri generali), vor fi aduşi în SR aferentă. Dacă instrucţiunea este de tip LOAD / STORE, va fi încărcată într-o SR numai dacă există un buffer (LB sau SB) disponibil. Dacă nu există disponibilă o SR sau un buffer, rezultă că avem un hazard structural şi instrucţiunea va aştepta până când aceste resurse se eliberează. 2) Execuţie - dacă un operand nu este disponibil, prin monitorizarea magistralei CDB de către SR ("snooping" - spionaj), se aşteaptă respectivul operand. În această fază se testează existenţa hazardurilor de tip RAW între instrucţiuni. Când ambii operanzi devin disponibili, se execută instrucţiunea în unitatea de execuţie corespunzătoare.

136 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 138 3) Scriere rezultat (WB) - când rezultatul este disponibil se înscrie pe CDB şi de aici în FPR sau într-o SR care aşteaptă acest rezultat ("forwarding"). De observat că nu există pe parcursul acestor faze testări pentru hazarduri de tip WAR sau WAW, acestea fiind eliminate prin însăşi natura algoritmului de comandă după cum se va vedea imediat. De asemenea, operanzii sursă vor fi preluaţi de către SR direct de pe CDB prin "forwarding" când acest lucru este posibil. Evident că ei pot fi preluaţi şi din FPR în cazurile în care nu vor fi produşi de instrucţiunile din staţiile de rezervare sau din unităţile de execuţie. O SR deţine 6 câmpuri cu următoarea semnificaţie: OP - codul operaţiei (opcode) instrucţiunii din SR. Qj, Qk - codifică pe un număr de biţi unitatea de execuţie (ADD, MUL, etc.) sau numărul bufferului LB, care urmează să genereze operandul sursă aferent instrucţiunii din SR. Dacă acest câmp este zero, rezultă că operandul sursă este deja disponibil într-un câmp Vi sau Vj al SR sau pur şi simplu nu este necesar. Câmpurile Qj, Qk sunt pe post de TAG, adică atunci când o unitate de execuţie sau un buffer LB "pasează" rezultatul pe CDB, acest rezultat se înscrie în câmpul Vi sau Vj al acelei SR al cărei TAG coincide cu numărul sau numele unităţii de execuţie sau bufferului LB care a generat rezultatul. Vj, Vk - conţin valorile operanzilor sursă aferenţi instrucţiunii din SR. Remarcăm că doar unul dintre câmpurile Q respectiv V sunt valide pentru un anumit operand. BUSY - indică atunci când este setat că SR şi unitatea de execuţie aferentă sunt ocupate momentan. Regiştrii generali FPR şi bufferele SB deţin fiecare de asemenea câte un câmp Qi, care codifică numărul unităţii de execuţie care va genera data ce va fi încărcată în respectivul registru general respectiv care va fi stocată în memoria de date. De asemenea, deţin câte un bit de BUSY. Bufferele SB deţin în plus un câmp care conţine adresa de acces precum şi un câmp care conţine data de înscris. Bufferele LB conţin doar un bit BUSY şi un câmp de adresă. Spre a exemplifica funcţionarea algoritmului să considerăm în continuare o secvenţă simplă de program maşină: Start Execuţie WB 1. LF F6, 27(R1) x x x 2. LF F2, 45(R2) x x 3. MULTF F0, F2, F4 x 4. SUBF F8, F6, F2 x 5. DIVF F10, F0, F6 x

137 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore ADDF F6, F8, F2 x În continuare prezentăm starea SR şi a FPR în momentul definit mai sus, adică prima instrucţiune încheiată, a 2-a în faza de execuţie iar celelalte aflate în faza de startare. Situaţia staţiilor de rezervare în prima instanţă Tabelul 4.5. Tabelul 4.6. Starea regiştrilor generali în prima instanţă Din aceste structuri de date implementate în hardware, rezultă de exemplu că SR ADD1 urmează să lanseze în execuţie instrucţiunea SUBF F8, F6, F2. Valoarea primului operand (F6) se află deja în câmpul Vj unde a fost memorată de pe magistrala CDB ca urmare a terminării execuţiei primei instrucţiuni. Evident că rezultatul acestei instrucţiuni a fost preluat de pe CDB în registrul F6 dar şi în bufferul LB1. Al 2-lea operand al instrucţiunii SUBF nu este încă disponibil. Câmpul de TAG Qk arată că acest operand va fi generat pe CDB cu "adresa" LOAD2 (LB2) şi deci această SR va prelua

138 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 140 operandul în câmpul Vk de îndată ce acest lucru devine posibil. Preluarea acestui operand se va face de către toate SR care au un câmp de TAG identic cu LOAD2 (LB2). Să considerăm de exemplu că latenţa unităţilor ADD este de 2 impulsuri de tact, latenţa unităţilor MUL este de 10 impulsuri de tact pentru o înmulţire şi respectiv 40 impulsuri de tact pentru o operaţie de împărţire. "Starea" secvenţei anterioare în tactul premergător celui în care instrucţiunea MULTF va intra în faza WB va fi următoarea: Start Execuţie WB 1. LF F6, 27(R1) x x x 2. LF F2, 45(R2) x x x 3. MULTF F0, F2, F4 x x 4. SUBF F8, F6, F2 x x x 5. DIVF F10, F0, F6 x 6. ADDF F6, F8, F2 x x x În acest moment, starea staţiilor de rezervare şi a setului de regiştri generali va fi cea prezentată în tabelele 4.7 respectiv 4.8: Situaţia staţiilor de rezervare în a doua instanţă Tabelul 4.7.

139 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 141 Starea regiştrilor generali în a doua instanţă Tabelul 4.8. De remarcat că algoritmul a eliminat hazardul WAR prin registrul F6 între instrucţiunile DIVF şi ADDF şi a permis execuţia Out of Order a acestor instrucţiuni, în vederea creşterii ratei de procesare. Cum prima instrucţiune s-a încheiat, câmpul Vk aferent SR MUL2 va conţine valoarea operandului instrucţiunii DIVF, permiţând deci ca instrucţiunea ADDF să se încheie înaintea instrucţiunii DIVF. Chiar dacă prima instrucţiune nu s-ar fi încheiat, cîmpul Qk aferent SR MUL2 ar fi pointat la LOAD1 şi deci instrucţiunea DIVF ar fi fost independentă de ADDF. Aşadar, algoritmul prin "pasarea" rezultatelor în SR de îndată ce acestea sunt disponibile, evită hazardurile WAR. Pentru a pune în evidenţă întreaga "forţă" a algoritmului în eliminarea hazardurilor WAR şi WAW prin redenumire dinamică a resurselor, să considerăm bucla următoare: LOOP: LF F0, 0 (R1) MULTF F4, F0, F4 SD 0 (R1), F4 SUB R1, R1, #4 BNEZ R1, LOOP Considerând o unitate de predicţie a branchurilor de tip "branchtaken", 2 iteraţii succesive ale buclei se vor procesa ca mai jos (tabelele 4.9): Start Execuţie WB LF F0, 0 (R1) x x MULTF F4, F0, F2 x SD 0 (R1), F4 x LF F0, 0 (R1) x x MULTF F4, F0, F2 x SD 0 (R1), F4 x Se observă o procesare de tip "loop unrolling" ("netezirea buclei") prin hardware (tabelele 4.9). Instrucţiunea LOAD din a 2-a iteraţie se poate

140 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 142 executa înaintea instrucţiunii STORE din prima iteraţie întrucât adresele de acces sunt diferite în câmpurile din buffere. Ulterior şi instrucţiunile MULTF se vor putea suprapune în execuţie. De remarcat deci hazardul de tip WAW prin F0 între instrucţiunile de LOAD s-a eliminat cu ajutorul SR şi a bufferelor SB şi LB. Tabelul 4.9. Contextul procesorului aferent buclei de program Arhitectura Tomasulo are deci avantajele de a avea logica de detecţie a hazardurilor distribuită şi prin redenumire dinamică a resurselor, elimină hazardurile WAW şi WAR. Acest lucru este posibil pentru că resursele tip sursă folosite şi aflate în starea "BUSY", nu se adresează ca nume de regiştri ci ca nume de unităţi de execuţie ce vor produce aceste surse. În schimb, arhitectura este complexă, necesitând deci costuri ridicate. Este necesară o logică de control complexă, capabilă să execute căutări / memorări asociative cu viteză ridicată. Având în vedere progresele mari ale tehnologiilor VLSI, variante uşor îmbunătăţite ale acestei arhitecturi se aplică practic în toate procesoarele superscalare actuale (pentru reducerea conflictelor, se folosesc mai multe busuri de tip CDB).

141 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 143 Acest mecanism de forwarding din arhitectura lui Tomasulo, are meritul de a reduce semnificativ din presiunea la "citire" asupra setului general de regiştri logici, speculând dependenţele RAW între instrucţiuni O ARHITECTURĂ REPREZENTATIVĂ DE PROCESOR SUPERSCALAR Având în vedere ideile de implementare a execuţiilor multiple din arhitectura lui Tomasulo, o arhitectură superscalară reprezentativă este prezentată în figura 4.6. Prin SR am notat staţiile de rezervare aferente unităţilor de execuţie ale procesorului. Acestea implementează printre altele bufferul "instruction window" necesar procesoarelor superscalare cu execuţie Out of Order. Numărul optim de locaţii al fiecărei SR se determină pe bază de simulare. Deşi performanţa maximă a unei asemenea arhitecturi ar fi de 6 instrucţiuni/ciclu, în realitate, bazat pe simulări ample, s-a stabilit că rata medie de execuţie este situată între 1-2 instrucţiuni / ciclu. În sub 1% din cazuri, măsurat pe benchmark-uri nenumerice, există un potenţial de paralelism mai mare de 6 instrucţiuni / ciclu în cazul unei arhitecturi superscalare "pure". Aceasta se datorează în primul rând capacităţii limitate a bufferului de prefetch care constituie o limitare principială a oricărui procesor, exploatarea paralelismului între instrucţiuni fiind limitată de capacitatea acestui buffer. În tehnologia actuală acesta poate memora între 8-64 instrucţiuni, capacităţi mai mari ale acestuia complicând mult logica de detecţie a hazardurilor RAW după cum am arătat (vezi paragraful 3.1). Prezentăm pe scurt rolul modulelor componente din această schemă tipică. Decodificatorul plasează instrucţiunile multiple în SR- urile corespunzătoare. O unitate funcţională poate starta execuţia unei instrucţiuni din SR imediat după decodificare dacă instrucţiunea nu implică dependenţe, operanzii îi sunt diponibili şi dacă unitatea de execuţie este liberă. În caz contrar, instrucţiunea aşteaptă în SR până când aceste condiţii vor fi îndeplinite. Dacă mai multe instrucţiuni dintr-o SR sunt simultan disponibile spre a fi executate, procesorul o va selecta pe prima din secvenţa de instrucţiuni.

142 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 144 Figura 4.6. Arhitectura tipică a unui procesor superscalar Desigur că este necesar un mecanism de arbitrare în vederea accesării CDB de către diversele unităţi de execuţie (UE). În vederea creşterii eficienţei, deseori magistralele interne sunt multiplicate. Prezentăm în figura 4.7 circulaţia informaţiei într-o structură superscalară puternică, similară cu cea implementată la microprocesorul Motorola MC Setul de regiştri generali (FILE) este multiplicat fizic, conţinutul acestor seturi fizice este identic însă în orice moment. Am considerat că UE- urile conţin şi staţiile de rezervare aferente. Din acest motiv, având în vedere mecanismul de "forwarding" implementat, comunicaţia între UE şi CDB s-a considerat bidirecţională.

143 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 145 Figura 4.7. Multiplicarea magistralelor şi a seturilor de regiştri Există 3 categorii de busuri comune şi anume: busuri rezultat (RB), busuri sursă (SB) si busuri destinaţie (CDB). N corespunde numărului maxim de instrucţiuni care pot fi lansate simultan în execuţie. Min (M, P) reprezintă numărul maxim de instrucţiuni care pot fi terminate simultan. Uzual se alege M = P. Există implementate mecanisme de arbitrare distribuite în vederea rezolvării tuturor hazardurilor structurale posibile pe parcursul procesărilor. Pe bază de simulare se încearcă stabilirea unei arhitecturi optimale. Astfel se arată că pentru o rată de fetch şi de execuţie de 4 instrucţiuni, procesarea optimă din punct de vedere performanţă/cost impune 7 busuri destinaţie, 4 unităţi de execuţie întregi şi 8 staţii de rezervare pentru unităţile LOAD / STORE. Pentru o asemenea arhitectură s-ar obţine o rată de procesare de 2.88 instrucţiuni / tact, măsurat însă pe benchmark-uri cu un puternic caracter numeric, favorizante deci (Livermore Loops). Ideea de bază este însă că hazardurile structurale se elimină şi aici prin multiplicarea resurselor hardware, deci fără pierderi de performanţă. Gradul de multiplicare trebuie însă stabilit prin simulări ample ori prin metode teoretice.

144 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 146 Buffer-ul de reordonare (paragraf preluat din cartea VINTAN N. LUCIAN Prediction Techniques in Advanced Computing Architectures (in limba engleza), Matrix Rom Publishing House, Bucharest, ISBN , 2007 (292 pg.; 3 ex. ULBS + 7 schimb interbibliotecar; cota Biblioteca ULBS ); #867 The present-day out of order issue superscalar microprocessor model (dynamic scheduling processors) is implemented as a speculative microarchitecture that actually fetches, issues and executes instructions based on branch prediction using R. Tomasulo s or closely related algorithms and a special data structure called ReOrder Buffer (ROB). This model extends the idea of instructions dynamic scheduling by introducing the possibility of speculative execution. The hardware that implements Tomasulo s algorithm can be extended to support speculation, only if the bypassing of results, which is needed to execute an instruction speculatively, is separated from the completion of an instruction (that consists in updating the memory or register file). Doing this separation, an instruction bypasses its results to other instructions, without performing any updates that might modify the CPU s logical state. When the instruction is no longer speculative, thus after its write-back stage, it updates the logical registers or data memory; this last phase is called instruction s commit. Separating the results bypassing from instructions completion makes possible to avoid imprecise exceptions during the out-of-order instructions processing. Adding this last commit phase to the instruction execution sequence, an additional set of hardware buffers is required, which hold the instructions results that have finished execution but have not yet committed. The Reorder Buffer structure implements these buffers. The Reorder Buffer is also used to pass the results of the out of order executed instructions through the reservation stations. The reservation stations buffer instructions only between the time they issue and the time they begin execution. In this architecture the ROB provides the register renaming function, as we ll further presented. Figure 1.1 shows the hardware structure of the processor including the ROB and Figure 1.2 presents ROB s structure.

145 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 147 Figure 1.1. A typical out-of-order superscalar microarchitecture Figure 1.2. Reorder Buffer s structure

146 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 148 Each reservation station (SR in Figure 1.1) has the following fields: Op instruction s operation code (opcode); Q j, Q k the ROB entries that will store the source operands, a value of zero (NULL) indicating that the source operand is already available in V j, V k, or that it is unnecessary; we called these Q fields potential operands. V j, V k the values of the instruction s source operands; for loads and stores the V j field is used to hold the address offset; we called these V fields actual operands. Addr holds the memory effective address for loads or stores; Dest supply the corresponding ROB entry s number representing the destination for the result produced by the execution unit. Busy indicates if a reservation station (SR) is available or not. The register file has also a field Q i indicating the number of the ROB entry that contains the operation whose result should be stored into the register. Excepting instructions fetch, the other six phases involved in pipeline instruction processing are the following: 1. Dispatch get the next instruction from the instruction s queue. If all reservation stations are full or the ROB is full (for example due to a Load with miss in level two cache being in the ROB s head), then instruction dispatch is stalled until both structures have available entries. If there is an empty reservation station and the tail of the ROB is free, the instruction is sent to the reservation station. Here is also implemented a routing algorithm to dispatch the instruction to the right reservation station (attached to the right execution unit). The Busy bit of the allocated reservation station is set and the Ready field of the ROB entry is reset. ROB is associatively searched in all its Dest fields using the source registers name. In the case of multiple hits, it is considered the last entry since the ROB entries are allocated in order. If an operand value is available in the ROB (Ready=1), it is written from the Value field into the reservation station fields V j / V k. If the operand value is not available (Ready=0), the number of ROB s entry attached to the operand is written into the reservation station fields Q j / Q k. In the case of a miss in the ROB the operand value is written from the register set into the reservation station fields V j / V k. The number of ROB s entry allocated for the value of the result is sent into the reservation station s Dest field. The destination register number is written into the Dest field of the ROB entry.

147 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore Issue if an operand is not yet available, the common data bus (CDB) is monitored and when the operand is available on the CDB it is placed into the corresponding reservation station. When both source operands are available, the instruction is issued to the appropriate execution unit. By delaying instruction s execution until their source operands are available, RAW dependences are detected. 3. Execute the corresponding functional unit executes the ALU instructions. In the case of loads and stores in this stage is calculated the data memory effective address. In the case of a taken branch, usually it is calculated the branch s target address. 4. Memory active only for load and store instructions. During this stage the result is written in the data-memory location (store) or loaded from the data-memory location into the destination register (store). The datamemory address was calculated during the previous stage. 5. Writeback when the result is available, it is put on the Common Data Bus (together with the ROB s entry number indicated by the reservation station s Dest field) and from there into the Value field of the corresponding ROB entry (its Ready field is set to 1). The Busy field of the corresponding reservation station is reset. The result is also written into the fields V j / V k of all those reservation stations that are waiting for it. In the case of a store instruction, if the value to be stored is available, it is written into the Value field of the ROB entry allocated for that store. If the value to be stored is not available, the CDB is monitored, and when the data-value is received, the Value field of the ROB entry is updated. 6. Commit The normal commit case occurs when an instruction reaches the head of ROB and its result is available (Ready=1). In this case, the result is written from the Val field of the ROB s entry into the destination register indicated by the Dest field of the ROB s entry or into a data-memory location and, after that, the instruction is squashed from the ROB. Thus, the in order commit is guaranteed by the in order dispatch, while the issue, execute and writeback stages can be processed out of order. When an incorrect predicted branch reaches the head of the ROB, the ROB is emptied and the execution is restarted with the correct successor of the branch. As it can be observed, in the case of speculative architectures it is very important when is performed the updating. Using the ROB, speculative executions are possible because the register file or data memory are updated with the result of an instruction only when that instruction is no longer speculative. ROB capacity is largely determined by how many instructions

148 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 150 may be executed in parallel between Dispatch and Commit. Of course branch prediction is crucial for exploiting instruction level parallelism between multiple basic-blocks. Each ROB entry contains four fields: Type, Dest, Value and the Ready field. The Type field indicates whether the instruction is a branch, a store, or a register operation (ALU operation or load). The Dest field supplies the register number for loads and ALU operations or the memory address for stores, where the instruction s result must be written. The Value field is used to hold the value of the result until the instruction commits. The Ready field indicates if the instruction has completed execution (the value is ready). ROB completely replaces the store buffers. ROB is usually implemented as a circular FIFO queue having associative search facilities. For a better understanding of the ROB functions we are analyzing the following problems: 1. What is happen in the <Tail_ROB> after the current instruction decode? If the <Tail_ROB> entry is free it will be allocated to the decoded instruction. After this ROB s Ready field will be reset on 0. In the Dest field it will be written the destination register s number. 2. When an ALU instruction will be introduced into a Reservation Station, what might be written in its Q fields? In the Q j and Q k fields it will be written the ROB locations indexes that will generate operand s value (after associative searches Opcode[Source_Reg1,2]=Dest[ROB]?). Obviously, if an operand is available its value will be introduced in the reservation station s V field. In this case the corresponding Q field will contain a NULL value. In the reservation station s Dest fields it will be introduced ROB location s index that was allocated to that concrete instruction (associative search Opcode[Dest_Reg]=Dest[ROB]? If yes, kdest[sr]; the corresponding ROB entry s index is noted with k). At the end of the execution s stage the functional execution unit will write the result in ROB at the address Dest. Now, the question is: what will happen if after these associative searches we ll obtain multiple hits in ROB? Answer: We ll consider the last hit location from the ROB. Why? Because the instructions were in order allocated in the ROB during the decode stage. But if one search is with miss? Answer: Then the register file will be accessed.

149 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore What is happen in ROB during the WriteBack stage? If the instruction produced a result it is written in ROB s Value field. Produced Data-Value ROB at address Dest[SR](k) AND Ready=1. The result s value is send also to the reservation stations (through the fields Vj / Vk). In the case of a Store, the value that must be written in the Commit stage is written in ROB s Value field. 4. What conditions must be fulfilled to start the Commit phase? Commit stage starts only if the instruction is already in the WriteBack stage and the corresponding ROB entry is in <Head_ROB> (in order commit). More precisely, Commit is doing if: <Instr.Head ROB> AND <Ready=1> AND <No_Exception> (If Exception=1 Blocking writes in register file) 5. Considering Dispatch, Issue, Exec, WriteBack, Commit stages, what of them are processing Out of Order. Why? Issue, Exec, and WriteBack because the operations results are written only in ROB and not in the CPU s logical registers. After an exception event, branch misprediction, etc. the processor s context might be recovered by evicting from the ROB all the instructions processed immediately after the exception s event. The instruction s result is written into the register file or data memory only during Commit stage. (Also see below the Commit phase s comments) 6. Why Commit phase is In Order processed? Its in order processing is guaranteed by the ROB s FIFO circular queue organization. Obviously Dispatch stage must be in order in this processing model, otherwise we can t guarantee that Commit will be in order. 7. What is the ROB s Dest field role? The Dest field contains destination register s name if the instruction really has a destination register. During Commit stage the value from ROB is written in the register file at the address Dest. After Dispatch it is associatively searched in ROB if Source_Reg=Dest[ROB].

150 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 152 As an alternative to ROB is the dynamic register renaming technique. This is based on a set of extended physical registers instead of using a ROB and reservation stations. During the Dispatch phase the destination register is renamed with a free physical register belonging to the extended set of registers. In this way, WAR (Write After Read) and WAW (Write After Write) instructions data dependences are avoided. After Commit stage this register become a logical register and the physical register becomes free (if there aren t instructions that use it as a source). The logic-physic conversion is done through a simple mapping table. As a register renaming advantage, the in order processes are simplified. As an alternative to this register deallocation process, the CPU has to wait for de-allocation until another instruction will modify that register. In this case a register might be allocated more that it is strictly necessary (MIPS R10000 case). MIPS R10000/120000, Alpha 21264, Pentium III, IV implemented register renaming technique, adding up to 80 extended physical registers. However, in the last 3-4 years there are some opinions considering that future processors must avoid a ROB centric design and move toward a checkpoint-oriented processing model. Check pointing means saving the CPU s state at appropriate points of execution in order to repair the processor to a known previous architectural state. ROB limits the microarchitecture s scalability, it does not scale efficiently as instruction window size increases. If an uncompleted instruction reaches the ROB s head, it blocks the ROB and, in the nearest time, also the instructions issue process (because the ROB would be full). The checkpointing key idea is that sometimes reconstructing CPU s logical state is more efficient than explicitly storing state like ROB-based approaches that record states every instruction. Checkpointing records state only at some selected execution points (miss-predicted branches, L2 cache miss Loads the so called memory wall problem, etc.) and will regenerate state for individual instructions only if it is necessary. Researchers show that such an approach is scalable and more efficient comparing with centralized ROB models. This solution will permit thousands of in-flight instructions, as Professor Mateo Valero s research group from UPC Barcelona already proposed (Kilo- Instruction Processors Project). The main challenge is to design such an architecture without so much resource enlargements (instruction queues, load/store queues, physical register file, etc.) and therefore permitting a high clock frequency.

151 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore PROBLEME SPECIFICE INSTRUCŢIUNILOR DE RAMIFICAŢIE ÎN ARHITECTURILE MEM Să considerăm o secvenţă de program care se execută astfel: PC= : I1 I2 I3 I4 I5 (branch condiţionat) PC= : I6 I7 I8 I9 (branch condiţionat) Dacă am presupune că BDS-ul este de 2 cicli, procesarea secvenţei de mai sus pe un procesor superscalar (VLIW) cu procesare In Order care poate aduce şi executa maxim 4 instrucţiuni / ciclu, s-ar desfăşura ca în Tabelul Se observă că pentru a compensa BDS-ul de 10 instrucţiuni, ar trebui introduse în acesta 10 instrucţiuni anterioare instrucţiunii I5 şi care să nu o afecteze. Acest lucru este practic imposibil, de unde rezultă că asemenea metode sunt inefective pentru procesoarele superscalare. Din acest motiv predicţia hardware a branch-urilor pe baza unui BTB sau a unei scheme corelate pe 2 nivele, este implementată deseori în aceste procesoare. Pentru ca metodele de predicţie prezentate pe larg în Capitolul 2 să funcţioneze şi în acest caz, sunt necesare câteva completări datorate aducerii şi execuţiei multiple a instrucţiunilor. Tabelul Efectul BDS-ului într-un procesor superscalar

152 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 154 Se va considera că o locaţie a memoriei cache de instrucţiuni conţine 4 câmpuri. Fiecare câmp la rândul său va fi format din: codul instrucţiunii respective, tag-ul format din biţii de adresă cei mai semnificativi, indexul de succesor (IS) şi indexul branch-ului în locaţie (IBL). Subcâmpul IS indică următoarea locaţie din cache- ul de instrucţiuni (I-Cache) predicţionată a fi adusă şi respectiv prima instrucţiune ce trebuie executată din cadrul acestei locaţii. Subcâmpul IBL indică dacă există sau nu o instrucţiune de salt în locaţia din cache şi dacă da, locul acesteia în cadrul locaţiei. Pentru secvenţa anterioară de program, intrările în memoria I-Cache se prezintă ca în figura 4.8 (IBL s-a exprimat în binar). Figura 4.8. Structura intrărilor I-Cache într-un procesor superscalar Aşadar subcâmpul IS pointează spre prima instrucţiune care trebuie executată în cadrul unei locaţii din cache, iar subcâmpul IBL spre o eventuală instrucţiune de salt din cadrul aceleiaşi locaţii, predicţionată că se va face. Adresa completă a instrucţiunii la care se face saltul este conţinută în tabelele de predicţie corespunzătoare. În continuare se vor prezenta câteva tehnici software utilizate în procesoarele superscalare şi VLIW. Aceste alternative pot simplifica mult complexitatea hardware a procesorului. După cum se va vedea, utilizarea unor optimizări software elimină necesitatea execuţiei Out of Order a instrucţiunilor, a bufferului "instruction window", redenumirii dinamice a regiştrilor, etc. Microprocesoare multi-microthread. Abordarea multithread pentru acoperirea latenţelor paragraf preluat/adaptat din lucrarea: VINTAN N. LUCIAN Predictie si speculatie in microprocesoarele avansate, Editura Matrix Rom, Bucuresti, ISBN ,

153 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore , Bibl. Univ. Sibiu - cota (10 ex. la Biblioteca ULBS + 10 schimb interbibliotecar) O altă categorie de microarhitecturi interesante o constituie aşa numitele microprocesoare multi-microthread (cu microfire multiple de execuţie simultană). Un procesor multi-microthread (PMT) deţine abilitatea de a procesa simultan instrucţiuni provenite din thread-uri ( microfire de execuţie ) diferite, facilitând astfel execuţia programelor multifir. În accepţiunea clasică din ingineria software, un thread (fir) reprezintă o secvenţă atomică de program, concurentă, recunoscută de către sistemele de operare care permit mai multor fire de execuţie să ruleze, alocându-le resursele necesare în acest scop. Firele au propriul spaţiu de cod şi de stivă dar, spre deosebire de taskuri, nu au zonă de date proprie, ele comunicând printr-o zonă partajată de memorie (zona de date a taskului respectiv). Firele partajează informaţia de stare a taskului precum şi anumite resurse hardware alocate acestuia. În general, un task este constituit din mai multe fire de execuţie. În general, variabilele partajate au aceeaşi adresă şi acelaşi înţeles pentru toate firele. În accepţiunea din arhitectura calculatoarelor, mai largă, un microfir de execuţie poate fi un task, un fir de execuţie dintr-un task dar poate fi constituit şi din entităţi soft de granularitate mai mare, precum iteraţii ale unei bucle de program, secvente de cod cvasi-independente sau proceduri (rutine) din cadrul unui fir, toate executabile în paralel (execuţie concurentă). După cum se va arăta în continuare, firele se activează-dezactivează pe parcursul execuţiei programelor, comunicând între ele şi sincronizându-şi activităţile. Această tehnică se mai numeşte uneori, în mod inexact, multitasking, deoarece programul se poate ocupa cvasi-simultan de mai multe sarcini. PMT gestionează o listă a microthread-urilor active şi decide într-o manieră dinamică asupra instrucţiunilor pe care să le lanseze în execuţie. Coexistenţa mai multor thread-uri active permite exploatarea unui tip de paralelism numit Thread Level Parallelism (TLP), adică paralelism la nivelul microfirelor concurente de execuţie [Sil99, Vin00]. În continuare, pentru comoditate, vom numi un microfir pur şi simplu, fir sau thread. Instrucţiunile din thread-uri diferite, fiind în general independente între ele, se pot executa în paralel ceea ce implică grade superioare de utilizare ale resurselor precum şi mascarea latenţelor unor instrucţiuni aflate în execuţie. În acest ultim sens, de asemenea, gestiunea branch-urilor este simplificată, latenţa acestora putând fi (măcar parţial) acoperită de instrucţiuni aparţinând unor thread-uri diferite şi deci independente de condiţia de salt. De asemenea, efectul defavorabil al miss-urilor în cache-uri poate fi contracarat prin acest multithreading (dacă un thread generează un miss în cache de ex.,

154 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 156 CPU-ul - Central Processing Unit - poate continua procesele de aducere ale instrucţiunilor din cadrul celorlalte thread-uri). Aşadar groapa semantică între conceptele de procesare multithreading a aplicaţiilor HLL şi procesorul hardware convenţional este umplută tocmai de aceste microprocesoare multithread. Aşadar TLP-ul reprezintă o extensie, de granularitate mai mică (deci granulă mai mare!), a paralelismului ILP (Instruction Level Parallelism) exploatat de către microprocesoarele superscalare. Deşi multithreading-ul îmbunătăţeşte performanţa globală, se cuvine a se remarca faptul că viteza de procesare a unui anumit thread în sine, nu se îmbunătăţeşte prin această tehnică. Mai mult, este de aşteptat chiar ca viteza de procesare pentru fiecare thread în parte să se degradeze întrucât resursele CPU trebuiesc partajate între toate thread-urile active din structurile pipeline. Cu alte cuvinte, acest TLP se pretează a fi exploatat, fireşte, în modurile de lucru ale sistemelor cu multiprogramare sau/şi multithread. Partajarea multiplelor resurse hardware în vederea implementării mai multor contexte de procesare aferente fiecărui thread, implică probleme dificile în cadrul unui PMT (mecanisme de aducere a mai multor instrucţiuni de la adrese diferite şi necontigue, structuri de predicţie multiple, lansarea în execuţie a mai multor instrucţiuni aparţinând unor thread-uri distincte etc). Simularea şi optimizarea unor arhitecturi PMT devin extrem de sofisticate, clasicele benchmark-uri în sine, nemaifiind aici de mare ajutor. Trebuie lucrat în medii software bazate pe multiprogramare sau multihreading ceea ce nu este deloc uşor de implementat şi mai ales de simulat şi evaluat. Latenţa memoriei principale este o problema esenţială în sistemele de calcul actuale, numită şi memory wall. În cadrul unui sistem multimicroprocesor cu memorie partajată ( DSM - Data Shared Memory ), procesoarele sunt conectate la modulele fizice de memorie printr-o reţea de interconectare, mai mult sau mai puţin complexă (unibus, crossbar, interconectări dinamice multinivel etc. [Hen02, Vin00b]). Dacă un anumit procesor doreşte să citească o anumită locaţie din spaţiul logic unic de adresare el va lansa o cerere de acces printr-o instrucţine tip Load (sau un mesaj, în cadrul sistemelor multiprocesor de tip message passing, cu memorii fizic distribuite dpdv logic). Aceasta se va propaga de la procesor la modulul fizic de memorie prin intermediul reţelei de interconectare. Modulul de memorie va furniza data procesorului după un timp de citire propriu, intrinsec circuitului, prin intermediul aceleiaşi reţele de interconectare. Intervalul de timp dintre cererea procesorului şi recepţionarea datei de către acesta se numeşte latenţă. În cazul sistemelor actuale aceasta devine tot mai mult o problemă datorită creşterii vitezei microprocesoarelor cu cca. 58 % pe an în timp ce timpul de acces al memoriilor de tip DRAM scade cu doar 7 % pe an (după alţi autori acesta

155 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 157 scade doar cu cca. 3-4% pe an, în timp ce densitatea de integrare a acestor memorii creşte cu 40-60% pe an [Hen02]). De exemplu, pe un multiprocesor Alpha Server 4100 SMP având 4 procesoare Alpha la 300 MHz, latenţele la citire sunt: 7 tacte (deci cca. 23 ns) în cazul unui miss pe nivelul 1 de cache (L1) şi hit pe nivelul 2 de cache (L2). 21 tacte în cazul unui miss pe nivelul L2 şi hit pe L3 (situat pe placa de bază). 80 tacte pentru miss în întreaga ierarhia de cache-uri şi accesarea DRAM-ului (memoria principală). 125 de tacte pentru un miss care a fost servit din cache-ul altui procesor (se adaugă aici şi latenţa reţelei de interconectare). Pentru un multiprocesor DSM de tip Silicon Graphics SGI Origin 2000, care poate interconecta până la 1024 de microprocesoare, ne putem aştepta la latenţe de 200 de tacte sau chiar mai mult. Este evident că aceste latenţe se traduc în principal prin aşteptări prohibitive din partea procesorului respectiv. Una dintre strategiile arhitecturale relativ recente de a contracara problema latenţelor mari ale sistemelor de memorie o constituie microprocesoarele multithread dedicate (MMT). În principiu, multitheading-ul a migrat aici din nivelul înalt al sistemelor de operare şi aplicaţiilor HLL (High Level Languages), pe verticală, în cadrul firmwareului şi al hardware-ului microprocesoarelor moderne. Printr-o definiţie succintă şi intuitivă, un MMT diferă de un microprocesor convenţional de tip monofir ("single threaded") prin faptul că facilitează procesarea simultană a mai multor instrucţiuni aparţinând unor thread-uri ("fire de execuţie") diferite, care însă sunt toate candidate înspre a fi executate de către procesor. Similar cu procesoarele convenţionale "monofir", starea unui MMT constă în contextul momentan al regiştrilor procesorului respectiv al memoriei; diferenţa specifică rezidă în faptul că există în principiu mai multe perechi (PC - Program Counter şi SP Stack Pointer) şi seturi logice de regiştri generali, permiţându-se astfel diferenţierea contextelor momentane aferente thread-urilor în curs de execuţie. Iată deci, într-un mod succint şi principial, cum aceste caracteristici specifice ale MMT-urilor facilitează procesarea multithread de la nivelul sistemului de operare şi aplicaţiilor HLL până la cel al hardware-ului. O altă noţiune importantă este aceea de fir de execuţie blocant respectiv neblocant ("blocking or non-blocking"). Noţiunea se referă la blocarea fluxurilor de instrucţiuni în cadrul structurilor pipeline de procesare a acestora, structuri indispensabile procesoarelor multithreading dedicate de

156 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 158 care ne ocupăm aici. Un fir blocant poate stagna structura pipeline de procesare pe un procesor convenţional "monofir", în cazul apariţiei unor hazarduri specifice (structurale, de date, de ramificaţie, latenţe etc.) [Hen02]. În schimb pe o arhitectură MMT aceste blocări pot fi evitate prin activarea unui alt thread realizată prin comutarea de context (context switching). Comutarea de context într-un procesor "monofir", în general consumă timp (salvări/restaurări de contexte în/din memorie), astfel încât mascarea unui blocaj datorat unui miss în cache este practic compromisă, cel puţin parţial. Firele neblocante sunt datorate componentei scheduler (reorganizator sau optimizator de cod) din cadrul compilatorului. Acesta partiţionează programul în mici thread-uri (microthreads), activarea unuia făcându-se numai când toate datele devin disponibile. Aceleaşi mecanisme hardware trebuie utilizate pentru a sincroniza comunicaţiile interprocese între firele aflate în stare de aşteptare. Ca exemple de fire blocante, acestea sunt firele P(Osix), Solaris sau chiar întregi procese Unix din cadrul unui sistem de operare Unix de tip multifir dar chiar şi microthread-uri generate de către compilator pentru a exploata potenţialul unui MMT. În cadrul acestui scurt paragraf ne vom ocupa de acele arhitecturi MMT dedicate şi care se dezvoltă pe cunoscutele structuri de procesoare RISC, EPIC (Explicitly Instruction Set Computing vezi Intel IA 64, procesorul Ithanium [Vin00b]), VLIW ( Very Long Instruction Word ) şi superscalare [Vin00]. Principala cerinţă pentru un MMT o constituie abilitatea de a gestiona 2 sau mai multe fire în paralel şi un mecanism care să permită comutarea acestora. Fireşte, această comutare este de dorit să fie cât mai rapidă (0 3 tacte CPU). Ea este facilitată, după cum am mai menţionat, de mai multe PC-uri, SP-uri şi seturi de regiştri logici, asociate firelor de execuţie. În principiu, după modul în care un fir intră şi respectiv iese în/din execuţie, există 3 modalităţi distincte de procesoare multithreading [Sil99,Wall99]: prin întreţeserea instrucţiunilor în fiecare ciclu ("cycle by cycle interleaving"), adică în fiecare ciclu CPU o instrucţiune dintr-un alt thread este adusă şi lansată în structura pipeline. prin întreţeserea blocurilor de instrucţiuni, adică instrucţiunile dintrun thread sunt, executate până când apare un hazard ce produce o latenţă. Acest eveniment implică o comutare de context, deci sunt activate instrucţiunile din alt bloc ( block interleaving ). multithreading simultan ("simultaneous multithreading"), care constă într-o combinare a multithreading-ului cu procesarea superscalară.

157 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 159 Instrucţiunile - aparţinând sau nu unor fire de execuţie diferite - sunt lansate înspre unităţile funcţionale aferente procesorului superscalar în mod simultan, în vederea ocupării optimale a resurselor acestuia. De menţionat că o problemă criticabilă a MMT-urilor constă în faptul că în general procesează mai puţin performant decât un procesor superscalar un program de tip "monofir". Foarte important, în toate cazurile este necesar un scheduler (planificator) de thread-uri (hardware, software, hibrid). Acesta exploateaza efectiv paralelismul TLP. Figura 4.1 Modele de procesoare 4.1 Modelul cu întreţesere la nivel de ciclu (cycle by cycle interleaving) În cadrul acestui model, numit în literatura de specialitate şi "finegrain multithreading", procesorul comută pe un alt thread după fiecare aducere de instrucţiune. În principiu, prin multiplexarea instrucţiunilor aparţinând unor thread-uri diferite, pot fi anulate hazardurile RAW (Read After Write), hazardurile de ramificaţie, latenţele etc. De asemenea, comutarea de context are în acest caz latenţă nulă. Modelul necesită un număr de thread-uri cel puţin egal cu numărul de nivele ale structurii pipeline, pentru a fi certă anularea hazardurilor mai sus-amintite. De remarcat totuşi că multiplexările instrucţiunilor din cadrul mai multor thread-uri limitează viteza de procesare a unui singur thread. Există în esentă 2 modalităţi de a limita această deficienţă [Sil99]: a) O tehnică statică integrată în scheduler care permite lansarea succesivă în structura pipe a unor instrucţiuni din cadrul aceluiaşi thread,

158 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 160 dacă acestea nu sunt dependente de instrucţiuni anterioare aflate în curs de procesare în structură. Această tehnică implică modificarea structurii ISA (Instruction Set Architecture) a microprocesorului în sensul adăugării câtorva biţi fiecărui format de instrucţiune. Aceşti biţi vor informa câte instrucţiuni din acelaşi thread o vor urma succesiv pe cea lansată în structură. Fireşte, tehnica aceasta (numită "dependence lookahead") se pretează a fi utilizată atunci când numărul de thread-uri este insuficient. b) O tehnică hardware, prin care se adaugă structurii pipeline o logică suplimentară de detecţie şi rezolvare a hazardurilor, atunci când se procesează un singur thread, deci un hibrid între un CPU clasic şi unul de tip multithreading cu întreţesere. Unul dintre cele mai cunoscute sisteme muliprocesor, care utilizează până la 256 de procesoare MMT este "Tera Multithreaded Architecture" (MTA), proiectat şi implementat la Seattle, S.U.A., de către cunoscuta companie Tera Computer Co. Un procesor are un kernel ISA de tip VLIW, utilizează modelul cu întreţesere a thread-urilor la nivel de ciclu, suportă 128 de thread-uri distincte (numite "streams") pe care le comută la fiecare 3 ns (f=333 MHz). În vederea creşterii vitezei de procesare monofir se foloseşte tehnica "dependence lookahead", anterior descrisă pe scurt. MTA deţine maximum 512 module de memorie interconectate la procesoare printr-o reţea toroidală 3D având 2816 noduri de rutare. MTA poate suporta pâna la 512 Gocteţi de memorie internă şi poate atinge o performanţă maximă, pe benchmark-uri numerice în virgulă mobilă, de 256 GFLOPS. Sistemul exploatează paralelismul pe toate cele 3 nivele de granularitate succesive: la nivel de instrucţiuni (ILP) [Vin00], la nivelul intermediar de thread-uri (TLP) cât şi la nivel de aplicaţii paralele (multiprogramare propriu-zisă). Prima achiziţie comercială a unui asemenea supercomputer s-a făcut în aprilie 1998 de către "San Diego Supercomputer Center" din S.U.A. 4.2 Modelul cu întreţeserea blocurilor (block interleaving) Acest model numit şi "coarse grain multithreading", execută un singur thread până în momentul în care apare un eveniment ce declanşează comutarea de context. Uzual, asemenea evenimente apar atunci când fluxul de instrucţiuni din structura pipeline se blochează datorită unei operaţii având o latenţă relativ mare. Comparând cu modelul anterior, se remarcă faptul că în acest caz este necesar un număr mai mic de thread-uri distincte; de asemenea performanţa procesării unui singur thread este comparabilă cu

159 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 161 cea obtenabilă pe un procesor clasic (superscalar) echivalent d. p. d. v. logic (al ISA Instruction Set Architecture). Time Resources (e.g. FUs) Figura. Modelul de procesare superscalar, ineficient (un thread)

160 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 162 Time Resources (e.g. FUs) Figura. Modelul Block Interleaving (2 threaduri; 1 + 1) Există principial 2 modalităţi de comutare a thread-urilor în cadrul acestui model: statică şi respectiv dinamică. În continuare se vor explicita sumar fiecare dintre aceste tehnici de comutare a blocurilor. a. Comutare statică În acest caz comutarea este dictată prin program (compilator) printr-o instrucţiune special dedicată. În principiu, timpul de comutare este aici de un tact având în vedere că după aducerea şi decodificarea instrucţiunii care comută thread-ul, aceasta trebuie evacuată din structura pipe. Dacă nu s-ar evacua, timpul de comutare ar fi nul dar întârzierea ar fi determinată de însăşi procesarea acestei instrucţiuni "inutile". Există implementări în care comutarea de context nu se face explicit ca mai sus ci într-un mod implicit. Astfel de exemplu, după introducerea fiecărei instrucţiuni de citire din memorie (LOAD), se determină comutarea, tocmai spre a se evita latenţa miss-ului potenţial. Fireşte în cazul unui hit în cache-ul de date, comutarea

161 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 163 este practic inutilă. O altă posibilitate constă în comutarea după fiecare scriere în memoria de date (STORE). Raţiunea ar fi legată şi de asigurarea consistenţei secvenţiale a memoriilor locale în sistemele multimicroprocesor, adică asigurarea faptului că un procesor citeşte din memorie ultima dată înscrisă în respectiva locaţie. În fine, în cadrul altor cercetări se comută thread-urile (blocurile mai precis) după fiecare instrucţiune de ramificaţie (branch), în scopul reducerii latenţelor aferente sau renunţării la implementarea predicţiei acestora. În schimb, performanţa în cazul "monofir" este drastic diminuată în acest caz. Totuşi, această modalitate este eficientă în cazul blocurilor cu branch-uri dificil de predicţionat (ex. branch-uri indirecte generate de polimorfismele din programarea obiectuală, branch-uri nepolarizate într-un anumit context dinamic unbiased branches etc.) b. Comutarea dinamică În acest caz comutarea blocurilor se declanşează datorită unui eveniment dinamic, apărut deci pe parcursul procesării hardware (run-time). În general, comutarea dinamică implică timpi mai mari de comutare decât cea statică datorită necesităţii evacuării tuturor instrucţiunilor din structura pipe, anterioare stagiului care a declanşat comutarea. Şi aici, ca şi în cazul comutării statice, putem avea câteva modalităţi distincte de comutare. Astfel se poate comuta blocul pe un miss în cache. Din păcate acesta este detectat relativ târziu în structura pipeline, implicând astfel timpi de comutare considerabili. O altă modalitate poate comuta pe activarea unui semnal specific ("switch-on-signal"), dat de o întrerupere, derută ori de recepţionarea unui mesaj. În fine, se întâlnesc şi modele de comutare hibride de gen "conditional switch", în care comutarea se realizează printr-o instrucţiune specială (caracter static), însă numai în cazul în care aceasta întâlneşte un anumit context dinamic (instanţă hardware). Astfel de exemplu o instrucţiune tip "switch" poate fi introdusă de către compilator după un grup de instrucţiuni LOAD/STORE. Dacă grupul a generat "miss"-uri comutarea se face, altfel nu. Un exemplu experimental de astfel de procesor, a fost implementat la prestigioasa universitate MIT din S.U.A. şi se numeşte "MIT Sparcle", întrucât derivă din arhitectura binecunoscutului procesor RISC numit Sparc (Sun Co.). Procesorul este scalar, are 4 contexte independente (seturi de regiştri, PC-uri, SP-uri şi stări). Aşadar, pot fi procesate simultan în structura pipe până la 4 thread-uri distincte. Sunt implementate strategiile de comutare a blocurilor de tip "cache miss" şi respectiv "switch-on signal", anterior descrise succint. Comutarea se face prin hardware deci, de către controller-ul de cache (care implementează inclusiv protocoale de coerenţă

162 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 164 pentru conectarea în sisteme multimicroprocesor). Penalizarea de comutare e relativ mare, de 14 tacte. Figura 4.2 Structura procesorului MIT Sparcle 4.3 Modelul multithreading simultan Cele două modele de procesoare multithreading anterior prezentate sunt modele eficiente pe procesoare scalare RISC ori chiar procesoare de tip VLIW sau EPIC. Modelul "simultaneous multithreading" (SMT) derivă din arhitectura superscalară, cea mai populară actualmente, care lansează în execuţie mai multe instrucţiuni independente în fiecare ciclu şi, asemenea MMT-urilor, conţine resurse hardware pentru contexte multiple procesate simultan. Instrucţiunile independente procesate simultan intr-un ciclu pot proveni din acelaşi fir (ILP) sau din fire distincte (TLP), de unde avantajul

163 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 165 esenţial şi popularitatea acestor microprocesoare (numite de compania Intel, hyperthreaded). Datorită faptului că un procesor SMT exploatează simultan atât paralelismul la nivel de instrucţiuni cât şi cel la nivel de thread-uri, adaptându-se astfel în mod dinamic la cele 2 tipuri de paralelisme (ILP şi TLP), performanţa acestuia o depăşeşte, teoretic cel puţin, pe cea a modelelor anterioare. Preţul constă însă într-o organizare hardware ceva mai complexă decât în cazurile anterioare. Într-un model de procesor SMT lansarea instrucţiunilor în execuţie se poate face din buffer-e de prefetch separate, în mod simultan. Aşadar, unităţile funcţionale ale procesorului pot fi ocupate cu instrucţiuni din thread-uri diferite, mascându-se astfel latenţele instrucţiunilor provenite dintr-un singur fir de execuţie. Un procesor SMT menţine starea fiecărui thread în hardware şi permite comutarea rapidă între thread-uri. Unitatea de fetch instrucţiuni poate aduce în fiecare ciclu, instrucţiuni din thread-uri distincte, crescând astfel probabilitatea de a aduce instrucţiuni nespeculative. Fireşte unitatea de fetch poate avea o politică selectivă relativă la thread-urile pe care le alege. Spre exemplu, ar putea să le aleagă pe acelea care oferă un beneficiu de performanţă imediat. Procesoarele SMT pot fi organizate principial în două moduri distincte: Ele pot partaja prin thread-uri diferite, în mod agresiv, nişte resurse (ex. buffer-ele de prefetch şi structurile pipeline de procesare ale instrucţiunilor) atunci când aceste thread-uri nu conţin suficient de mult paralelism la nivel de instrucţiuni. Deci procesoarele SMT adaugă un hardware minimal la superscalarele convenţionale; complexitatea adăugată se referă în principiu la un tag (identificator) adăugat fiecărei instrucţiuni dintr-un anumit thread, seturi multiple de regiştri logici etc. Al 2-lea model organizaţional multiplică toate buffer-ele interne ale procesorului superscalar, asociind câte un astfel de buffer unui thread, la un moment dat (v. figura 4.1, dreapta). Această organizare este mai complexă dar face modelul SMT mai natural, raportat la paradigma multithreading, conducând astfel la o alocare mai eficientă a thread-urilor la resursele hardware existente. De observat că arhitectura SMT nu dă rezultate deosebite pe programe tip monofir. Problema esentiala este cea a scheduler-ului care exploateaza ILP si TLP deopotriva.

164 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 166 Superscalar Fine-Grained Coarse-Grained Multiprocessing Simultaneous Multithreading Thread 1 Thread 2 Thread 3 Thread 4 Thread 5 Idle slot Figura. Comparatie intre diferite modele de procesare (superscalar, multithreads, multi-cores) O interesantă cercetare pe bază de simulare a avut loc la Universitatea din Washington, S.U.A. Arhitectura SMT era centrată pe o arhitectură superscalară cu posibilitatea lansării în execuţie a 8 instrucţiuni independente simultan precum şi cu posibilitatea procesării a 8 fire de execuţie. În fiecare ciclu de fetch instrucţiuni se aduc câte 8 instrucţiuni din 2 thread-uri diferite pe baza unui algoritm cu priorităţi rotitoare ("roundrobin"). Pentru simulare s-au folosit binecunoscutele benchmark-uri SPEC 98 care au fost executate simultan pe post de thread-uri distincte. Pe această configuraţie s-a obţinut o rată de execuţie de 6,64 instr./ciclu, remarcabil având în vedere că un procesor superscalar (monofir) echivalent, ar obţine doar cca. 2-3 instr./ciclu. De asemenea, studii relativ recente asupra eficienţei arhitecturilor SMT, cu posibilitatea pocesării a 8 fire de execuţie în procesarea bazelor de date şi respectiv multimedia, arată că

165 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 167 aceste arhitecturi realizează creşteri de performanţă de cca. 300 % în comparaţie cu arhitecturi monofir având resurse hardware/software similare. În [Mar99] se propune o abordare inedită care integrează predicţia valorilor în arhitecturile de tip multithread. Ideea de bază constă în execuţia concurentă a unor thread-uri speculative din cadrul programului. Acestea sunt determinate pe timpul rulării programului cu ajutorul predictorului de branch-uri. Fireşte că, în vederea execuţiei thread-urilor speculative împreună cu cele nespeculative, este necesar ca procesorul să ofere contexte hardware multiple. Fiecare thread va avea propria sa fereastră de instrucţiuni. O problemă esenţială este aceea a determinării efective a thread-urilor speculative. Spre exemplu, în cazul unei bucle de program, thread-urile speculative ar putea fi constituite din chiar iteraţiile buclei respective. Acesta este cazul proiectului STAMPede de la Universitatea Carnegie Mellon, SUA, condus de către profesorul Todd Mowry ( Pentru programele nonnumerice, caracterizate prin grade limitate de paralelism, este foarte probabil să existe inter-dependenţe între aceste thread-uri. O rezolvare simplă în acest sens ar consta în serializarea acestor dependenţe de date. Predicţia valorilor ar putea comprima lanţurile de instrucţiuni dependente, îmbunătăţind semnificativ performanţa acestor arhitecturi multifir. Cercetări laborioase au arătat că o asemenea arhitectură hibridă a implicat o creştere de performanţă de 40% faţă de o arhitectură superscalară monofir şi respectiv de 9% faţă de o arhitectură superscalară monofir având înglobat un predictor hibrid de valori. În concluzie, procesoarele multithread au apărut din necesităţi evidente de mapare a hardware-ului pe softurile actuale de nivel înalt care exploatează şi ele acest concept, încă mai de demult. Aceste MMT-uri şi în special procesoarele SMT constituie o tendinţă serioasă a actualei generaţii arhitecturale de microprocesoare (cea de a 4-a). Alături de reutilizarea dinamică a instrucţiunilor ( Dynamic Instruction Reuse tehnică de comprimare nespeculativă a lanţurilor de instrucţiuni dependente) şi predicţia valorilor instrucţiunilor ( Value Locality and Value Prediction tehnică speculativă), ce vor fi prezentate în semestrele următoare de studiu, dar şi de alte concepte arhitecturale, precum multiprocesoarele integrate pe un singur cip (multi and many-cores), cred că SMT-urile se vor impune în continuare, în vederea exploatării agresive a ILP şi TLP. Pipeline (faze) ILP (instructiuni) TLP (threads, resurse partajate) Multi & Many-Cores (tasks, procesoare distincte)

166 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore OPTIMIZAREA BASIC-BLOCK-URILOR ÎN ARHITECTURILE MEM Ca şi în cazul procesoarelor scalare, reorganizarea (scheduling) reprezintă procesul de aranjare a instrucţiunilor din cadrul unui program obiect astfel încât acesta să se execute într-un mod cvasioptimal din punct de vedere al timpului de procesare. Procesul de reorganizare a instrucţiunilor determină creşterea probabilităţii ca procesorul să aducă simultan din cache-ul de instrucţiuni mai multe instrucţiuni independente. De asemenea asigură procesarea eficientă a operaţiilor critice din punct de vedere temporal în sensul reducerii prin masacare a latenţelor specifice acestor operaţii. Se va aborda mai întâi problema optimizării " basic block"- urilor. De remarcat că schedulingul în procesoarele superscalare poate determina o simplificare substanţială a arhitecturii hardware aferentă acestora. Se va analiza acum spre exemplificare următoarea secvenţă de program: I1: ADD R1, R11, R12 I2: ADD R1, R1, R13 I3: SLL R2, R3, #4; R2<--R3 deplasat logic la stânga cu 4 poz. binare I4: AND R2, R1, R2 I5: ADD R1, R14, R15 I6: ADD R1, R1, R16 I7: ADD R1, R1, #6 I8: LD R1, (R1) I9: LD R4, (R4) I10: ADD R1, R4, R1 I11: OR R1, R1, R2 I12: ST R1, (R4) Considerând un procesor superscalar care decodifică simultan 4 instrucţiuni şi deţine 4 unităţi de execuţie (2 unităţi ALU, o unitate LOAD / STORE şi o unitate pentru deplasări / rotiri), procesul de execuţie al secvenţei anterioare s-ar desfăşura ca în Tabelul 4.11 (am presupus că doar instrucţiunile LOAD au latenţa de 2 cicli maşină):

167 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 169 Tabelul Execuţia unui program neoptimizat pe un procesor superscalar De remarcat că rata de procesare a acestei secvenţe este de 12 instrucţiuni per ciclu, adică 1,1 instrucţiuni / ciclu ( s-a considerat procesare In Order din punct de vedere al ferestrelor de execuţie şi respectiv Out of Order în cadrul unei ferestre de execuţie). Se observă că paralelismul potenţial al secvenţelor de instrucţiuni I1 - I4 respectiv I5 - I12 nu este exploatat. În continuare se va prezenta un algoritm de reorganizare în "basic block"-uri (unităţi secvenţiale de program) în vederea unei execuţii cvasioptimale pe un procesor superscalar sau VLIW PARTIŢIONAREA UNUI PROGRAM ÎN "BASIC- BLOCK"-URI Se are în vedere construirea grafului de control al unui program dat. Algoritmul de partiţionare constă principial în următorii 2 paşi: 1) Determinarea setului de lideri în cadrul programului. Se numeşte lider prima instrucţiune dintr-un program, instrucţiunea destinaţie a oricărei

168 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 170 instrucţiuni de branch sau orice instrucţiune următoare unei instrucţiuni de branch. 2) Partiţionarea programului în unităţi secvenţiale şi construirea grafului de control. Fiecare unitate secvenţială conţine un singur lider şi toate instrucţiunile de la acest lider până la următorul exclusiv. Se determină predecesorii imediaţi faţă de o unitate secvenţială de program. Poate fi un predecesor imediat al unei unităţi secvenţiale date orice unitate secvenţială care se poate executa înaintea unităţii date. Se determină succesorii unei unităţi secvenţiale de program. Se numeşte succesor al unei unităţi secvenţiale de program orice unitate secvenţială de program care poate să se execute după execuţia celei curente. În figura de mai jos (figura 4.9) se dă un exemplu de partiţionare a unui program dat în "basic block"-uri şi graful de control al programului. Figura 4.9. Partiţionarea unui program în basic-block-uri

169 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore CONSTRUCŢIA GRAFULUI DEPENDENŢELOR DE DATE ASOCIAT După cum se va vedea, în stabilirea unei secvenţe reorganizate de program în vederea unei procesări cvasioptimale pe un procesor superscalar sau VLIW, graful dependenţelor de date aferent unei unităţi secvenţiale de program, se va dovedi deosebit de util. Un arc în acest graf semnifică o dependenţă RAW între cele 2 stări. Instrucţiunile care utilizează date din afara unităţii secvenţiale de program se vor plasa în vârful grafului astfel încât în ele nu va intra nici un arc. Pentru o instrucţiune dată se caută în jos proxima dependenţă RAW. Cu aceste reguli simple, graful dependenţelor de date corespunzător secvenţei de program anterioare este prezentat mai jos (figura 4.10): Figura Graful dependenţelor de date asociat În stânga arcului este scrisă latenţa operaţiei respective. În dreapta arcului este scrisă latenţa maximă a drumului măsurată dintr-un vârf al arcului până în starea respectivă. Graful dependenţelor specifică deci relaţii de ordine între instrucţiuni absolut necesare execuţiei corecte a programului dat.

170 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 172 Graful precedenţelor Se obţine pe baza grafului dependenţelor de date în baza faptului că există cazuri în care acesta poate să nu cuprindă toate precedenţele necesare unei corecte reorganizări. Altfel spus, acest graf nu pune în evidenţă relaţiile de precedenţă strictă în lansarea în execuţie, impuse de către dependenţele de tip WAR respectiv WAW între instrucţiuni. De exemplu, între instrucţiunile I2 şi I5 există o dependenţă de tip WAW, iar între I4 şi I5 una de tip WAR. Aceste dependenţe ar obliga schedulerul să proceseze I2 şi I4 înaintea instrucţiunii I5. Şi totuşi aceste dependenţe (mai degrabă conflicte de nume) între secvenţele I1 - I4 şi respectiv I5-I10 pot fi eliminate prin redenumirea regiştrilor care determină dependenţele WAR şi WAW ( în cazul nostru registrul R1). Astfel, de exemplu, dacă în cadrul secvenţei de instrucţiuni I1-I4 se redenumeşte registrul R1 cu un alt registru disponibil în acel moment (de ex. cu R5), atunci secvenţele I1 - I4 şi respectiv I5 - I10 devin complet independente, permiţând o procesare paralelă mai accentuată. Redenumirea regiştrilor, ca şi în cazul procesoarelor scalare, se poate face static, adică prin software în momentul compilării, sau dinamic, prin hardware în momentul procesării. Trebuie deci redenumiţi acei regiştri care determină dependenţele WAR şi WAW între ramuri independente ale unităţii secvenţiale de program. Se arată că redenumirea regiştrilor creşte numărul regiştrilor utilizaţi şi timpul de viaţă al unui registru. Prin timp de viaţă al unui registru se înţelege numărul instrucţiunilor cuprinse între prima instrucţiune care actualizează respectivul registru şi respectiv ultima instrucţiune care-l citeşte. Aşadar, redenumirea regiştrilor crează dificultăţi alocării regiştrilor. Redenumirea se poate face pe durata timpului de viaţă al registrului. Important este însă faptul că prin redenumire, graful precedenţelor devine inefectiv, singurul care impune precedenţe reale, fundamentale, fiind deci graful dependenţelor de date prin dependenţele RAW intre instrucţiuni. Precedenţele impuse prin dependenţe WAR şi WAW au fost puse în evidenţă prin linii întrerupte în figura anterioară. (figura 4.10) De asemenea, pentru o corectă execuţie trebuie respectată ordinea instrucţiunilor LOAD / STORE, aşadar instrucţiunile I8 şi I9 trebuie să preceadă instrucţiunea I12. Această ultimă constrângere însă, nu introduce în cazul concret analizat precedenţe suplimentare în graful dependenţelor de date. Această problemă - numită şi analiză antialias - a fost detaliată în capitolul 3.

171 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore CONCEPTUL CĂII CRITICE Calea critică a grafului dependenţelor de date o reprezintă drumul cu latenţă maximă, fiind deci reprezentată în exemplul analizat aici de secvenţa de instrucţiuni I5, I6, I7, I8, I10, I11 şi I12. Latenţa acestei căi este de 8 cicli. Conceptul căii critice este important deoarece el indică faptul că după scheduling, profitând la maxim de paralelismul între instrucţiuni, programul se va putea executa în minimum 8 cicli, adică într-un timp egal cu latenţa căii critice. Prin strategia sa, schedulerul va trebui ca în fiecare ciclu, pe cât posibil, să execute câte o instrucţiune din calea critică încercând simultan să suprapună peste această instrucţiune şi alte instrucţiuni independente din program. Într-un procesor ipotetic având resurse infinite, schedulerul optim ar trebui pur şi simplu să urmeze calea critică, suprapunând peste operaţiile de aici operaţii din alte căi. În cazul apariţiei unui hazard WAW sau WAR între instrucţiuni trebuiesc redenumite registrele implicate. De exemplu în cazul anterior prezentat, simultan cu instrucţiunea I5 s-ar putea executa instrucţiunile I1, I3 şi I9 în condiţiile în care procesorul ar deţine suficiente resurse hardware (2 unităţi ALU, o unitate de shiftare şi o unitate LOAD / STORE în acest caz). De asemenea, datorită hazardului WAW dintre I1 şi I5, în instrucţiunea I1 ar trebui redenumit registrul R1 cu un alt registru disponibil din setul de regiştri. Cum în practică un procesor nu deţine totdeauna suficiente resurse în vederea executării celor de mai sus, rezultă că timpul de execuţie al programului reorganizat este mai mare sau cel mult egal cu latenţa căii critice. O reorganizare optimă ar însemna să se simuleze execuţia tuturor variantelor posibile de programe reorganizate şi să se măsoare ratele de procesare aferente, alegându-se varianta de program cu rata cea mai mare. Pentru programe mari acest deziderat ar implica uneori săptămâni sau chiar ani de procesare devenind deci prohibit. În practică se preferă algoritmi euristici bazaţi pe graful dependenţelor, care dau rezultate apropiate de cele optimale, în schimb necesită timpi de execuţie acceptabili. Aşadar problema optimalităţii teoretice a scheduling-ului, nu se pune din probleme de timp. În plus algoritmii euristici utilizaţi în practică dau rezultate bune ALGORITMUL "LIST SCHEDULING" (LS)

172 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 174 Este unul dintre cei mai reprezentativi algoritmi în acest sens, fapt pentru care va fi prezentat pe scurt. Timpul de execuţie este rezonabil întrucât algoritmul se execută într-o singură trecere prin graful dependenţelor, generând în majoritatea cazurilor reorganizări optimale. Algoritmul LS parcurge graful dependenţelor asociat unităţii secvenţiale de program de jos în sus. În fiecare pas se încearcă lansarea în execuţie a instrucţiunilor disponibile. După ce aceste instrucţiuni au fost puse în execuţie, instrucţiunile precedente devin disponibile spre a fi lansate în pasul următor. Fiecărei instrucţiuni i se ataşează un grad de prioritate egal cu latenţa căii instrucţiunii. Dacă apare un conflict la resurse hardware comune între 2 sau mai multe instrucţiuni, are prioritate instrucţiunea cu un grad de prioritate mai mare. Precizând că iniţial se setează un contor de cicli la o valoare maximă, paşii algoritmului sunt următorii: 1) Instrucţiunea cea mai prioritară dintre instrucţiunile disponibile în setul curent este lansată în execuţie dacă nu necesită o resursă ocupată în acest ciclu. 2) Dacă o instrucţiune a fost pusă în execuţie în pasul 1, resursele utilizate de aceasta vor fi setate ca fiind ocupate pentru un număr de cicli egali cu latenţa instrucţiunii. Pentru exemplul nostru se va considera latenţa instrucţiunilor LOAD de 2 cicli, iar latenţa celorlalte instrucţiuni de un ciclu. 3) Dacă instrucţiunea a fost lansată în execuţie în pasul 1 ea va fi ştearsă din lista instrucţiunilor disponibile în acel ciclu. Dacă instrucţiunea nu a fost lansată în execuţie datorită unui conflict, reorganizarea va continua cu o altă instrucţiune disponibilă. 4) Se repetă paşii 1-3 până când nu mai există nici o instrucţiune disponibilă în acest ciclu. 5) Se decrementează contorul de cicli. 6) Se determină următorul set de instrucţiuni disponibile. Precizăm că o instrucţiune este disponibilă dacă diferenţa între numărul ciclului în care a fost lansată în execuţie instrucţiunea succesoare şi numărul ciclului curent este egală cu latenţa instrucţiunii. 7) Dacă setul determinat la pasul 6 este consistent se trece la pasul 1. În caz contrar, reorganizarea este completă. Aplicarea algoritmului pe graful din exemplul considerat generează următoarea ordine de execuţie a instrucţiunilor (Tabelul 4.12).

173 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 175 Tabelul Ordinea de execuţie a instrucţiunilor în urma optimizării Execuţia instrucţiunilor pe un procesor superscalar In Order Issue cu 4 unităţi de execuţie se va face ca în tabelul de mai jos (tabelul 4.13): Execuţia programului optimizat Tabelul De remarcat că în ciclul 4 a existat un conflict structural între instrucţiunile I8 şi I9. S-a dat prioritate instrucţiunii I8 pentru că are un grad de prioritate superior. Invers n-ar fi putut fi pentru că I8 şi I7 sunt

174 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 176 dependente RAW, de unde rezultă necesitatea prioritizării după latenţa nodurilor respective. Pe această secvenţă de program se obţine o rată de procesare de 12 / 8 = 1.5 instr./ciclu faţă de doar 1.1 instr. / ciclu cât era rata de procesare a variantei de program nereorganizate, executată pe acelaşi procesor superscalar. O altă observaţie foarte importantă este aceea că schedulingul poate îmbunătăţi semnificativ gradul de utilizare al resurselor hardware, după cum de altfel se poate observa şi în cazul analizat aici. O variantă de algoritm similar care însă ar parcurge graful de sus în jos, ar genera următoarea execuţie (Tabelul 4.14): O altă posibilă execuţie a programului optimizat Tabelul Latenţa instrucţiunii I8 şi dependenţa RAW între I8 şi I10, au impus ca în ciclul 4 să nu se execute nici o operaţie. Performanţa este însă şi în acest caz de 1.5 instr. / ciclu. Este evident că performanţa unui procesor superscalar de tip In Order Issue care procesează un basic-block reorganizat optimal, este mai bună decât performanţa unui procesor superscalar Out of Order care procesează programul neoptimizat pentru că în al doilea caz paralelismul între instrucţiuni este limitat de capacitatea bufferului de prefetch (instruction window). În literatură sunt citate 2 variante principiale de realizare a reorganizărilor software, între care există un compromis fundamental. Prima este metoda postscheduling, care implică după compilare mai întâi alocarea regiştrilor, iar apoi reorganizarea propriu-zisă. În acest caz reorganizatorul este constrâns la nişte false dependenţe datorită faptului că alocatorul de regiştri reutilizează un registru cât mai mult posibil, rezultând un timp de

175 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 177 viaţă mai mic al acestuia, ceea ce duce la false dependenţe de date care se rezolvă de către scheduler prin redenumirea regiştrilor (în exemplul nostru a fost necesară redenumirea registrului R1). A doua metodă se numeşte prescheduling şi presupune mai întâi realizarea reorganizării codului obiect, iar apoi alocarea regiştrilor. În acest caz este posibil ca alocatorul de regiştri să nu poată păstra toate variabilele în regiştri, deoarece schedulerul prin redenumire măreşte timpul de viaţă al regiştrilor utilizaţi. Algoritmul LS pune la dispoziţia structurii hard paralelismul la nivel de instrucţiuni dintrun program, pe care structura respectivă îl exploatează la maxim. În continuare vom aborda problema optimizării globale a programelor pentru procesoarele cu execuţie multiplă a instrucţiunilor PROBLEMA OPTIMIZĂRII GLOBALE ÎN CADRUL PROCESOARELOR MEM În continuare vom prezenta câteva tehnici software legate de optimizarea programelor pentru procesoarele superscalare şi VLIW. În paragraful precedent s-au prezentat câteva tehnici în vederea optimizării "basic-block"-urilor (optimizare locală). Optimizarea "basic-block"-urilor aferente unui program nu implică în mod necesar optimizarea întregului program datorită problemelor legate de instrucţiunile de ramificaţie. Reorganizarea programelor care conţin branch-uri este mai dificilă întrucât aici "mutările" de instrucţiuni pot cauza incorectitudini ale programului reorganizat care ar trebui corectate. Această optimizare se mai numeşte şi optimizare globală. Problema optimizării globale este una de mare actualitate şi interes, întrucât paralelismul la nivelul basic-block-urilor, după cum arătau încă din anii '70 pionieri ca Michael Flynn, este relativ scăzut (2-3 instrucţiuni). Deoarece majoritatea programelor HLL sunt scrise în limbaje imperative şi pentru maşini secvenţiale cu un număr limitat de registre în vederea stocării temporare a variabilelor, este de aşteptat ca gradul de dependenţe între instrucţiunile adiacente să fie ridicat. Aşadar pentru mărirea nivelului de paralelism este necesară suprapunerea execuţiei unor instrucţiuni situate în basic-block-uri diferite, ceea ce conduce la ideea optimizării globale. Numeroase studii au arătat că paralelismul programelor de uz general poate atinge în variante idealizate (resurse hardware nelimitate, renaming perfect, analiză antialias perfectă, etc.) în medie instrucţiuni

176 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 178 simultane. De remarcat că schedulerele actuale, cele mai performante, raportează performanţe cuprinse între 3-7 instrucţiuni simultane. Se apreciază ca realiste obţinerea în viitorul apropiat a unor performanţe de instrucţiuni simultane bazat pe îmbunătăţirea tehnicilor de optimizare globală. Problema optimizării globale este una deschisă la ora actuală, având o natură NP - completă. Se prezintă în continuare în acest sens doar tehnica numită "Trace Scheduling", datorită faptului că este oarecum mai simplă şi mai clar documentată. Consider că marea majoritate a tehnicilor de optimizare globală nu au încă o justificare teoretică foarte solidă, bazânduse deseori pe o euristică dependentă de caracteristicile arhitecturii. Ele au drept scop execuţia unei instrucţiuni cât mai repede posibil, prin mutarea instrucţiunilor peste mai multe basic- block-uri. Constrângerile sunt date în principal de resursele hardware limitate. Pentru claritate, se va considera în continuare că instrucţiunile de salt nu conţin BDS-uri TEHNICA "TRACE SCHEDULING" (TS) Este atribuită cercetătorului american Joshua Fischer, pe atunci la Universitatea din New York, S.U.A., care a implementat-o în cadrul calculatorului VLIW numit BULLDOG( 1986). O implementare mai veche a acestei tehnici a fost legată de optimizarea microprogramelor în arhitecturi microprogramate orizontal. Se defineşte o cale ("Trace") într-un program ce conţine salturi condiţionate, o ramură particulară a acelui program legată de o asumare dată a adreselor acestor salturi. Rezultă deci că un program care conţine n salturi condiţionate va avea 2n posibile căi (trace-uri). Aşadar, o cale a unui program va traversa mai multe unităţi secvenţiale din acel program. În figura următoare (figura 4.11) se prezintă un program compus din 2 căi distincte, şi anume TRACE1 şi TRACE2.

177 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 179 Figura Exemplu de trace-uri pe o secvenţă de program Tehnica TS este similară cu tehnicile de reorganizare în "basic block"- uri, cu deosebirea că aici se va reorganiza o întreagă cale şi nu doar un basic block. În esenţă, ea se bazează pe optimizarea celor mai probabile căi în a fi executate. Spre exemplificare să considerăm o secvenţă de program C şi secvenţa de program obiect obţinută prin compilare: a[ i ] = a[ i ]+1; if (a[ i ] < 100) { count = count +1; *(b + sum) = *( b + sum) + a[ i ];} 1: SLL R1, i, 2 2: ADD R1, R1, base_a 3: LD R2, (R1); a[ i ] 4: ADD R2, R2, 1; a[ i ]+1 5: ST R2, (R1); asignare a[ i ] 6: CPLT R1, R2, 100; a[ i ] < 100? 7: JMPF R1, LABEL 8: ADD count, count, 1 9: ADD R1, base_b, s_off; adresa lui b[ sum] 10: LD R3, (R1) 11: ADD R3, R3, R2 12: ST R3, (R1) LABEL: Pentru a putea aplica TS compilatorul trebuie să aibă criterii rezonabile de predicţie a salturilor condiţionate, în vederea construirii căilor cu cea mai mare probabilitate de execuţie. În general, predicţia software se face pe baza informaţiilor rezultate din anterioară execuţia programului

178 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 180 neoptimizat (profilings) sau a altor algoritmi euristici înglobaţi în compilator. Execuţia secvenţei anterioare pe un procesor superscalar care decodifică 4 instrucţiuni simultan şi deţine 5 unităţi de execuţie se va face ca în Tabelul S-a considerat că saltul condiţionat nu se va face şi că procesorul execută In Order. Execuţia trace-ului neoptimizat Tabelul Figura Graful de control aferent secvenţei de optimizat

179 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 181 Datorită paralelismului limitat al acestei secvenţe se obţine o rată medie de execuţie de doar o instr. / ciclu. Graful de control al acestei secvenţe este complus din doar 2 basic block-uri ca în figura Figura Graful dependenţelor pentru trace-ul considerat Se va considera că programul compilator a ales calea prin care saltul nu se face spre a fi optimizată. Aşadar, instrucţiunea de salt va fi tratată în acest caz ca oricare alta. Graful precedenţelor de date asociat secvenţei anterioare de program este prezentat în figura Pentru a elimina dependenţele WAR şi WAW între cele 2 ramuri paralele, vom redenumi R1 cu un alt registru disponibil (RS1) pe ramura 9, 10, 11, 12. De remarcat că această problemă se datorează alocatorului de regiştri din cadrul compilatorului. Aplicând acum algoritmul LS pe graful dependenţelor de date aferent căii respective, obţinem următoarea ordine inversă de execuţie (v. Tabelul 4.16).

180 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 182 Tabelul Ordinea de execuţie în urma optimizării Aşadar, execuţia se va face în 7 cicli ca mai jos: 1)1 1: SLL R1, i, 2 2)2 2: ADD R1, R1, base_a 3)3,9 3: LD R2, (R1) 9)10 9: ADD RS1, base_b, s_off 5)4,8 10: LD R3, (RS1) 6)5,6,11 4: ADD R2, R2, 1 7)12,7 8: ADD count, count, 1 5: ST R2, (R1) 6: CPLT R1, R2, : ADD R3, R3, R2 12: ST R3, (RS1) 7: JMPF R1, LABEL LABEL: Aşadar prin suprapunerea operaţiilor din cele 2 basic block-uri s-a obţinut o rată de procesare de 1.71 instr. / ciclu. Problema care apare însă este: ce se întâmplă dacă saltul se face? Răspunsul ar consta în utilizarea unor coduri de compensaţie pentru predicţiile incorecte. Tehnica TS presupune mutarea instrucţiunilor dintr-un basic block în altul şi asta presupune anumite compensaţii în vederea păstrării corectitudinii programului reorganizat. Prezentăm mai jos compensaţiile necesare atunci când o instrucţiune e mutată dintr-un basic block într-unul succesor respectiv predecesor (figura 4.14).

181 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 183 Figura Compensaţii la migrarea instrucţiunilor dintr-un basic-block în altul În exemplul prezentat am avut o migrare a întregului bloc 8-12 în blocul precedent 1-7, deci compilatorul va trebui să introducă în al 2-lea bloc instrucţiuni de compensare în vederea anulării unor operaţii, absolut necesare atunci când saltul se face, ca mai jos: 1: SLL R1, i, 2 2: ADD R1, R1, base_a 3: LD R2, (R1) 9: ADD RS1, base_b, s_off 10: LD R3, (RS1) 4: ADD R2, R2, 1 8: ADD count, count, 1 5: ST R2, (R10) 6: CPLT R1, R2, : ADD RS3, R3, R2 12: ST RS3, (RS1) 7: JMPF R1, C2 C1: JMP LABEL C2: SUB count, count, 1 C3: ST R3, (RS1) LABEL: În vederea anulării operaţiei *(b+sum) = *(b+sum) + a[ i ] în cazul în care saltul se face, s-a introdus de către compilator linia C3. Pentru ca

182 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 184 această anulare să fie posibilă a fost necesară redenumirea registrului R3 cu un altul disponibil (RS3 aici) în instrucţiunile I11 şi I12. Altfel, instrucţiunea I11 ar fi alterat R3 şi deci anularea asignării variabilei *(b+sum) în memorie ar fi fost imposibilă. De remarcat similitudinea între corecţiile soft şi tehnicile hardware de execuţie speculativă prin care se redenumesc dinamic resursele procesorului. Johnson prezintă o serie de caracteristici arhitecturale cu scopul facilizării implementării tehnicii TS. Compensarea este eficientă numai dacă ciclii suplimentari introduşi prin aceasta nu depăşesc numărul ciclilor eliminaţi prin tehnica TS. O compensare eficientă presupune: - O acurateţe ridicată a predicţiei branch-urilor de către compilator, obţinută prin statistici rezultate din rularea programului. În acest sens programele numerice se pretează mai bine la TS decât cele de uz general. - Procentaj relativ scăzut al instrucţiunilor de ramificaţie din program. - Codurile de compensaţie să fie posibile şi fezabile. - Paralelism hardware pronunţat în vederea procesării codurilor de compensare cu introducerea unui număr minim de cicli suplimentari. Într-un program dat, reorganizatorul selectează căile pentru scheduling, utilizând tehnici de predicţie software. Pentru început se aplică algoritmul TS pentru calea cea mai probabilă de a fi executată. Pe timpul acestui proces se vor adăuga coduri de compensare. Apoi se selectează următoarea cale considerată cea mai probabilă. Aceasta va fi de asemenea reorganizată prin tehnica TS. Reorganizarea se referă inclusiv la posibilele coduri compensatoare introduse de către procesul anterior de reorganizare. Algoritmul TS se va repeta pentru fiecare cale în parte. Pentru limitarea timpului de reorganizare, referitor la căile mai puţin frecvente în execuţie, se poate renunţa la optimizarea globală în favoarea optimizării exclusiv a basic block-urilor componente prin algoritmul LS. Nu există încă criterii clare care să stabilească momentul în care optimizarea TS să fie abandonată. O situaţie oarecum ironică este legată de optimizarea programelor pentru procesoare superscalare datorită faptului că în acest caz logica hardware de lansare în execuţie a instrucţiunilor va relua în mod redundant căutarea instrucţiunilor independente. Această operaţie este inutilă fiind realizată anterior de către optimizatorul software. Din acest motiv, acesta ar trebui să marcheze grupele de instrucţiuni paralelizate, astfel încât hardware-ul să nu mai reia inutil această operaţie. Într-un asemenea context, procesarea Out of Order a instrucţiunilor caracteristică majoră şi complexă a multor procesoare superscalare apare ca fiind complet inutilă. Este încă o dovadă a faptului că paradigma procesării instrucţiunilor trebuie să fie una relativ simplă, dar în acelaşi timp nu mai simplă decât este necesar în virtutea unor principii de eficienţă, flexibilitate şi compatibilitate.

183 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore OPTIMIZAREA BUCLELOR DE PROGRAM Este foarte importantă pentru că în buclele de program se pierde cea mai mare parte a timpului de execuţie aferent respectivului program, după regula binecunoscută care afirmă că " 90% din timp execută cca. 10% din program". Iată de ce optimizarea buclelor reprezintă o preocupare esenţială la ora actuală TEHNICA "LOOP UNROLLING" Pentru ilustrarea principiului de optimizare, să considerăm următoarea buclă de program: for (i = 0; i < 64; i + +) { sum + = a[ i ];} Din compilarea acestei bucle rezultă următoarea secvenţă de program obiect tip RISC: LOOP: 1:LD R1, (a_ptr) 2:ADD a_ptr, a_ptr, 4 3:CLT count, a_ptr, end_ptr 4:ADD sum, sum, R1 5:JMPTcount, LOOP Execuţia a două iteraţii succesive pe un procesor superscalar "in order issue" se va desfăşura ca în tabelul de mai jos (Tabelul 4.17). Tabelul Execuţia buclei neoptimizate

184 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 186 S-a considerat că procesorul aduce 4 instrucţiuni simultan şi deţine 5 unităţi de execuţie distincte (BRN - unitate de execuţie a instrucţiunilor de ramificaţie). Se remarcă faptul că în acest caz rata de procesare este de 1.25 instr./ciclu sau altfel spus de 0.25 bucle/ciclu. După aplicarea tehnicii Loop Unrolling de 2 ori secvenţa anterioară devine: LOOP: 1: LD R1, (a_ptr) 2: ADD a_ptr, a_ptr, 4 3: ADD sum, sum, R1 4: LD R1, (a_ptr) 5: ADD a_ptr, a_ptr, 4 6: ADD sum, sum, R1 7: CLT count, a_ptr, end_ptr 8: JMPT count, LOOP Reorganizând basic block-ul precedent prin metoda LS anterior descrisă, obţinem următoarea secvenţă de program: LOOP: 1: LD R1, (a_ptr) 2: ADD a_ptr, a_ptr, 4 4: LD R2, (a_ptr) 5: ADD a_ptr, a_ptr, 4 7: CLT count, a_ptr, end_ptr 3: ADD sum, sum, R1 6: ADD sum, sum, R2 8: JMPT count, LOOP Execuţia acestei bucle pe acelaşi procesor superscalar se va face ca în Tabelul 4.18: Execuţia buclei optimizate Tabelul S-a obţinut astfel o rată medie de procesare de 2 instr. / ciclu sau 0.5 bucle / ciclu, deci practic performanţa s-a dublat faţă de exemplul precedent. Se pune problema: ce se întâmplă dacă numărul de iteraţii este necunoscut în momentul compilării? Pentru aceasta să considerăm secvenţa de mai jos:

185 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 187 for (i = 0; i < n ; i + +) { sum + = a[ i ] ; } Această secvenţă va fi compilată ţinând cont şi de aplicarea tehnicii LU ca mai jos: LOOP: 1: LD R1, (a_ptr) 2: ADD a_ptr, a_ptr, 4 3: ADD sum, sum, R1 4: CLT count, a_ptr, end_ptr 5: JMPF count, EXIT 6: LD R1, (a_ptr) 7: ADD a_ptr, a_ptr, 4 8: ADD sum, sum, R1 9: CLT count, a_ptr, end_ptr 10: JPMT count, LOOP EXIT: Graful de control corespunzător acestei secvenţe este prezentat în figura Figura Graful de control asociat buclei netezite Aşadar, în astfel de cazuri după aplicarea tehnicii LU se obţine o cale formată din două sau mai multe basic block-uri concatenate. Pentru optimizare se poate aplica algoritmul TS asupra grafului de control, dar aceasta poate complica şi reduce sever eficienţa tehnicii loop unrolling.

186 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore TEHNICA "SOFTWARE PIPELINING" Tehnica software pipelining (TSP) este utilizată în reorganizarea buclelor de program astfel încât fiecare iteraţie a buclei de program reorganizată să conţină instrucţiuni aparţinând unor iteraţii diferite din bucla originală. Această reorganizare are drept scop scăderea timpului de execuţie al buclei prin eliminarea hazardurilor intrinseci, eliminând astfel stagnările inutile pe timpul procesării instrucţiunilor. Prezentăm principiul acestei tehnici bazat pe un exemplu simplu. Aşadar să considerăm secvenţa de program următoare: LOOP: LD F0, 0(R1) ADD F4, F0, F2 SD 0(R1), F4 SUBI R1, R1, #8 BNEZ R1, LOOP Bucla realizează modificarea unui tablou de numere reprezentate în virgulă mobilă, prin adăugarea unei constante conţinută în registrul F2 la fiecare dintre acestea. De remarcat că hazardurile RAW între instrucţiunile I1, I2 respectiv I2, I3 determină stagnări în procesarea pipeline a instrucţiunilor acestei bucle. Într-o primă fază TSP desfăşoară, însă doar în mod simbolic, bucla în iteraţii succesive eliminând actualizarea contorului şi saltul înapoi. iteraţia i: LD F0, 0(R1) ADD F4, F0, F2 SD 0(R1), F4 iteraţia i+1: LD F0, 0(R1) ADD F4, F0, F2 SD 0(R1), F4 iteraţia i+2: LD F0, 0(R1) ADD F4, F0, F1 SD 0(R1), F4 În a doua fază, instrucţiunile selectate din cele trei iteraţii se grupează în cadrul unei noi bucle ca mai jos: LOOP: SD 0(R1), F4; memorează în M(i) ADD F4, F0, F2; modifică scalarul M(i-1) LD F0, - 16(R1); încarcă elementul M(i-2) SUBI R1, R1, #8; BNEZ R1, LOOP; Observăm că prin pipeline-izarea instrucţiunilor din cadrul acestei bucle reorganizate s-au eliminat hazardurile anterioare şi deci stagnările

187 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 189 implicate de către acestea. Bucla se execută pe un procesor pipeline scalar în doar 5 impulsuri de tact, adică la viteză maximă asumând o predicţie perfectă a saltului. De remarcat că pe un procesor superscalar cu suficiente unităţi de execuţie primele 3 instrucţiuni s-ar putea executa simultan, ceea ce pe varianta originală a buclei nu se putea din cauza hazardurilor RAW. Aşadar TSP este deosebit de eficientă pe procesoarele cu execuţie multiplă a instrucţiunilor. De multe ori este necesară intervenţia hardului sau a softului pentru eliminarea posibilelor hazarduri WAR care apar în cadrul buclei reorganizate. Totuşi, pentru a fi funcţională, bucla anterioară are nevoie de un preambul şi respectiv un postambul. Preambulul necesar constă în execuţia instrucţiunilor din iteraţiile 1 şi 2 care nu au fost executate în cadrul buclei (LD - 1, LD - 2, ADD - 1). Analog, postambulul constă în execuţia instrucţiunilor care nu au fost executate în ultimele 2 iteraţii (ADD - ultima, SD - ultimele 2 iteraţii). LD F0, (R1) iteratia 1 ADD F4, F0, F2 iteratia 1 PREAMBUL LD F0, -8(R1) iteratia 2 LOOP: SD 0(R1), F4; ADD F4, F0, F2; LD F0, - 16(R1); SUBI R1, R1, #8; BNEZ R1, LOOP; iteratia (i)/1/n-2; memorare (i+1)/2/n-1; prelucrare (i+2)/3/n; incarcare SD (R1), F4 (n-1)-a iteratie ADD F4, F0, F2 (n), ultima iteratie POSTAMBUL SD -8(R1), F4 (n) Alături de tehnica LU, TSP este des utilizată în optimizarea buclelor de program. Spre deosebire de LU, aceasta consumă mai puţin spaţiu de cod. Frecvent, cele 2 tehnici sunt combinate în vederea creşterii performanţei. Tehnica LU se concentrează pe eliminarea codurilor redundante din cadrul buclelor (actualizări contoare, loop-uri). Bucla se procesează la viteză maximă doar pe parcursul iteraţiilor desfăşurate. TSP încearcă în schimb, obţinerea unei viteze mari de execuţie pe întreg timpul procesării buclei.

188 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore ARHITECTURI CU TRANSPORT DECLANŞAT Arhitecturile cu transport declanşat (TTA - Transport Triggered Architectures) reprezintă o expresie limită a filosofiei RISC de exploatare a paralelismului instrucţiunilor. Apariţia lor (Universitatea din Delft, Olanda, 1992) a fost determinată de slăbiciunile modelelor superscalar şi VLIW, datorate în special gradului scăzut de utilizare al resurselor hardware (unităţi funcţionale, busuri interne, regiştri generali, etc) şi complexităţii ridicate. Esenţa TTA constă în separarea transportului datelor, de prelucrarea lor efectivă. Dacă în arhitecturile convenţionale (OTA-Operation Triggered Architectures) declanşarea execuţiei unei operaţii este iniţiată chiar de către operaţia (instrucţiunea) respectivă, în cadrul TTA această declanşare este iniţiată de către un transport al operandului sursă într-un aşa-numit registru trigger (T), ataşat fiecărei unităţi funcţionale din sistem. Un procesor TTA este compus din unităţi funcţionale complet independente, interconectate printr-o aşa-zisă reţea de transport. Fiecare unitate funcţională deţine 3 regiştri: registrul operand (O), registrul trigger (T) şi registrul rezultat (R). Transportul şi înscrierea unui operand în registrul T, determină automat activarea unităţii funcţionale respective. După cum am mai subliniat, un procesor TTA deţine o singură instrucţiune (MOVE - transfer), care se poate executa condiţionat pe 2 variabile de gardă de tip boolean. Planificarea mutărilor între diversele unităţi funcţionale (FU-Functional Unit) devine o sarcină software a compilatorului, nemaifiind integrată hardware în CPU ca în cazul clasic (OTA). Desigur că unităţile funcţionale cu latenţă mai mare de un tact pot fi pipeline-izate. De menţionat că având o singură instrucţiune, logica de decodificare TTA practic nu există. Cele două figuri care urmează, 4.16 şi 4.17, prezintă schema bloc de principiu a unui procesor TTA şi respectiv pipeline-izarea unei anumite unităţi funcţionale.

189 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 191 Figura Schema bloc a unei arhitecturi TTA Figura Pipeline-izarea execuţiei în cazul unei arhitecturi TTA În continuare se prezintă 2 exemple: o "instrucţiune" de adunare şi respectiv una de salt condiţionat, implementate în TTA. ADD R3, R2, R1 R1-->ADD_O, R2-->ADD_T (declanşare) ADD_R-->R3 if R2 = R3 goto Adr R2-->EQ_O, R3-->EQ_T EQ_R-->B1 (var. booleană) [B1]Adr-->PC (execuţie condiţionată)

190 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 192 De remarcat ca sunt posibile mai multe transporturi, funcţie de lărgimea de bandă a reţelei de transport. Intervalul de timp dintre declanşare şi mutarea rezultatului trebuie controlat prin software astfel încât să acopere latenţa unităţii funcţionale respective. Avantajele TTA Datorită simplităţii hardware a logicii de decodificare, control şi planificare a instrucţiunii, procesoarele TTA permit frecvenţe de tact extrem de ridicate. Mai mult, separarea unităţilor funcţionale de reţeaua de transport permite pipeline-izarea optimală a FU. Numărul de regiştri generali poate fi redus drastic datorită faptului că trebuie stocate mai puţine date temporare, multe dintre aceste date circulând direct între FU-uri, fără ca să trebuiască să fie memorate într-un registru de uz general. Stagiile pipeline şi regiştrii operanzi sunt utilizaţi pe post de regiştri temporari. Un rezultat produs de o FU, dar care nu poate fi utilizat direct de alt FU, poate fi lasat temporar în unitatea FU care l-a produs, dacă acesta nu blochează alte rezultate anterior necesare, ale aceleiaşi FU. Interesant, aici bypassing-ul (forwarding-ul) datelor este gestionat prin program, spre deosebire de procesoarele superscalare care realizează acest proces prin hardware (vezi Algoritmul lui Tomasulo). Spre exemplificare se consideră două instrucţiuni RISC dependente RAW, ca mai jos: ADD R3, R1, R2 R1ADD_O, R2ADD_T; ADD R5, R3, R4 ADD_RADD_O, R4ADD_T, ADD_RR3; ADD_RR5; Se observă forwarding-ul realizat prin software (ADD_R-->ADD_O) şi care optimizează execuţia cu un ciclu. Ca urmare se reduce presiunea la citire asupra setului de regiştri generali, analog cu mecanismul lui Tomasulo, doar că aici prin software. Dacă în continuare compilatorul constată că timpul de viaţă aferent registrului R3 s-a încheiat, secvenţa anterioară devine mai simplă: ADD R3, R1, R2 R1ADD_O, R2ADD_T ADD R5, R3, R4 ADD_RADD_O, R4ADD_T ADD_RR5 Astfel se reuşeşte oprirea scrierii inutile în R3 şi deci reducerea presiunii la scriere asupra setului de regiştri, lucru principial imposibil la nivelul procesoarelor OTA.

191 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 193 Un alt avantaj al arhitecturilor TTA constă în flexibilitatea şi scalabilitatea performanţelor. Flexibilitatea constă într-o facilă schimbare a funcţionalităţii, în concordanţă cu aplicaţia specifică. Scalabilitatea este determinată în principal de posibilitatea adăugării de noi FU-uri, fără modifcări arhitecturale majore şi de mărirea capacităţii de transport în vederea creşterii gradului de paralelism. Divizarea operaţiilor în transporturi elementare oferă un grad de paralelism mai fin, care determină posibilităţi mai eficiente de scheduling static şi deci performanţe superioare. Structurile TTA se pretează foarte bine la proiectarea de procesoare dedicate unor aplicaţii specifice (ASP-Application Specific Processor), parametrii FU şi ai reţelei de transport putând fi setaţi în acord cu aplicaţia ţintă. Deşi mediatizate intens în literatura de specialitate, TTA-urile nu constituie în opinia mea, o paradigmă novatoare a conceptului de procesor, reprezentând mai degrabă o superclasă a arhitecturilor VLIW tradiţionale, cu deosebirea că "sparg" atomicitatea instrucţiunii maşină în aşa-zise transporturi. Se permite astfel un control mai mare al execuţiei din partea compilatorului, cu posibilităţi superioare de optimizare a codului. Performanţele par remarcabile, depăşind la nivel de simulare respectiv implementare cu FPGA-uri, cu 25-50% variante OTA echivalente (I-860). Cu toate că la ora actuală aceste procesoare există doar la nivel de prototip, firme comerciale serioase precum Intel şi Hewlett Packard au iniţiat cercetări în domeniul TTA şi deci n-ar fi deloc exclus ca unele idei să se regăsească în viitoarele microprocesoare avansate produse de aceste companii EXTENSII ALE ARHITECTURILOR MEM BAZATE PE REUTILIZAREA DINAMICĂ A TRACE - URILOR DE INSTRUCŢIUNI Din punct de vedere arhitectural se consideră că până la ora actuală au existat 3 generaţii de (micro)procesoare de succes comercial după cum urmează: - generaţia I caracterizată în principal prin execuţia secvenţială a fazelor (ciclilor maşină) aferente instrucţiunilor- maşină. Pionierii acestei generaţii sunt desigur inventatorii calculatorului numeric, inginerii Eckert şi Mauchly, alături de cel care ulterior a teoretizat şi a îmbogăţit conceptul, în persoana marelui om de ştiinţă american John von Neumann.

192 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore generaţia a II-a de procesoare, exploata paralelismul temporal aferent instrucţiunilor maşină prin suprapunerea fazelor (pipeline). Primul reprezentant comercial a fost sistemul CDC-6600 (1964) proiectat de către cel mai mare creator de calculatoare de înaltă performanţă şi totodată unul dintre pionierii supercalculatoarelor, Seymour Cray. În anii '80, (micro)procesoarele RISC scalare au reprezentat această generaţie (J. Cocke de la IBM şi D. Patterson de la Univ. Berkeley fiind doar doi dintre pionierii promotori ai acestor idei). - generaţia a III-a, cea curentă, este caracterizată de procesarea mai multor instrucţiuni independente simultan prin exploatarea unui paralelism spaţial la nivelul diverselor unităţi funcţionale de procesare. Execuţia instrucţiunilor se face Out of Order, utilizând deci tehnici de reorganizare (dinamică sau statică) a instrucţiunilor în vederea minimizării timpului global de execuţie. Pionierul acestei generaţii a fost sistemul anilor '60 IBM- 360/91 (printre proiectanţi Anderson, Sparacio, Tomasulo, Goldschmidt, Earle, etc.). La ora actuală generaţia aceasta este reprezentată prin microprocesoarele superscalare, VLIW, etc. De câţiva ani, în laboratoarele de cercetare (în special cele academice!) se întrezăresc câteva soluţii privind caracteristicile majore ale următoarei decade, generaţia a IV-a, pe care le vom analiza succint şi fatalmente incomplet, în continuare. În ultimii ani, procesul de proiectare al procesoarelor s-a modificat radical. Astăzi, accentul principal nu se mai pune pe implementarea hardware, ci pe proiectarea arhitecturii. Se porneşte de la o arhitectură de bază, care este modificată şi îmbunătăţită dinamic, prin simulări laborioase pe benchmark-uri reprezentative (Stanford, SPEC '92, '95, etc., pentru procesoarele de uz general). De exemplu, proiectanţii firmei Intel, pentru procesorul Intel Pentium Pro (P6), au pornit de la o structură iniţială care conţinea un pipeline cu 10 nivele, decodificator cu 4 instrucţiuni / ciclu, cache-uri separate pe instrucţiuni şi date de capacitate 32Ko fiecare şi un total de 10 milioane tranzistori. Comportarea fiecărei componente a arhitecturii (efectul capacităţii primului nivel (L1) cache, numărul de nivele în pipeline, comportarea logicii de predicţie a salturilor, numărul de unităţi funcţionale, etc.) a fost simulată soft prin rularea a aproximativ 200 benchmark-uri, cu peste 2 miliarde de instrucţiuni! Rezultatul final a impus un procesor cu un pipeline pe 14 nivele, 3 instrucţiuni decodificate în fiecare ciclu, 8Ko L1 cache de date şi 8Ko L1 cache de instrucţiuni, cu un total de aproximativ doar 5.5 milioane tranzistoare integrate. Costul proiectării este relativ mare şi include în principal elaborarea unei arhitecturi dinamice, scrierea unui compilator, de C in general, pe arhitectura respectiva, scheduler (optimizator) pentru codul obiect, simulator

193 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 195 puternic parametrizabil si complex, programe de interpretare a rezultatelor. De exemplu, microprocesorul MIPS-4000 s-a creat prin efortul a 30 de ingineri timp de 3 ani. Costul cercetării-proiectării a fost de 30 milioane dolari, iar cel al fabricării efective de numai 10 milioane dolari. Numai pentru simulare şi evaluare s-au consumat circa ore de procesare pe maşini având performanţe de 20 MIPS. Oricum, arhitecturile cu execuţii multiple şi pipeline-izate ale instrucţiunilor (superscalare, VLIW) dau deja anumite semne de "oboseală", limitările fiind atât de ordin tehnologic cât şi arhitectural. Caracteristicile arhitecturale complexe implică tehnologii tot mai sofisticate, încă nedisponibile. Pe de altă parte, performanţele lor cresc asimptotic pe actualele paradigme arhitecturale. Totuşi, schimbări fundamentale sunt mai greu de acceptat în viitorul apropiat, în primul rând datorită compilatoarelor optimizate, având drept scop exploatarea mai pronunţată paralelismului la nivel de instrucţiuni, deoarece acestea sunt deosebit de complexe şi puternic dependente de caracteristicile hardware. Există deja opinii care arată că arhitecturile superscalare şi VLIW conţin limitări fundamentale şi care ar trebui analizate şi eventual eliminate. Dintre aceste limitări amintim doar conflictele la resurse, datorate în principal centralizării acestora. O idee interesantă bazată pe descentralizarea resurselor are în vedere implementarea mai multor aşa numite "Instruction Windows" (IW)- un fel de buffere de prefetch multiple în locul unuia singur şi respectiv pe conceptul de multithreading. Lansarea în execuţie a instrucţiunilor se face pe baza determinării celor independente din fiecare IW. Desigur că trebuie determinate şi dependenţele inter- IW- uri. Ideea principală constă în execuţia paralelă a mai multor secvenţe de program aflate în IW- uri diferite, bazat pe mai multe unităţi funcţionale (multithreading). Astfel de exemplu, 2 iteraţii succesive aferente unei bucle de program pot fi procesate în paralel dacă sunt memorate în IW- uri distincte. O asemenea idee facilitează implementarea conceptelor de expandabilitate şi scalabilitate, deosebit de utile în dezvoltarea viitoare a arhitecturii. În esenţă, un procesor cu execuţii multiple ale instrucţiunilor este compus din 2 mecanisme decuplate: mecanismul de aducere (fetch) a instrucţiunilor pe post de producător şi respectiv mecanismul de execuţie a instrucţiunilor pe post de consumator. Separarea între cele 2 mecanisme (arhitectură decuplată) se face prin bufferele de instrucţiuni şi staţiile de rezervare, ca în figura Instrucţiunile de ramificaţie şi predictoarele hardware aferente acţionează printr-un mecanism de reacţie între consumator şi producător. Astfel, în cazul unei predicţii eronate, bufferul de prefetch trebuie să fie golit măcar parţial iar adresa de acces la cache-ul de

194 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 196 instrucţiuni trebuie şi ea modificată în concordanţă cu adresa la care se face saltul. Figura Arhitectură superscalară decuplată Pe baze statistice se arată că un basic-block conţine, pe programele de uz general, doar 4-5 instrucţiuni în medie, ceea ce înseamnă că rata de fetch a instrucţiunilor e limitată la cca. 5, aducerea simultană a mai multor instrucţiuni fiind inutilă (fetch bottleneck). Desigur, această limitare fundamentală ar avea consecinţe defavorabile şi asupra consumatorului, care ar limita principial şi rata medie de execuţie a instrucţiunilor (IR - Issue Rate) la această valoare. Progresele semnificative în algoritmii de lansare în execuţie impun însă depăşirea acestei bariere. În acest sens, cercetările actuale insistă pe îmbunătăţirea mecanismelor de aducere a instrucţiunilor prin următoarele tehnici: - predicţia simultană a mai multor ramificaţii / tact rezultând deci rate IR sporite (vezi conceptul Dual BTB, în cap. 3) - posibilitatea accesării şi aducerii simultane a mai multor basicblock-uri din cache, chiar dacă acestea sunt nealiniate, prin utilizarea unor cache-uri multiport - păstrarea unei latenţe reduse a procesului de aducere a instrucţiunilor, în contradicţie cu cele 2 cerinţe anterioare. Alţi factori care determină limitarea ratei de fetch a instrucţiunilor (FR- Fetch Rate) sunt: lărgimea de bandă limitată a interfeţei procesor - cache, missurile în cache, predicţiile eronate ale ramificaţiilor, etc. O paradigmă interesantă, situată în prelungirea conceptului de superscalaritate şi care poate constitui o soluţie interesantă faţă de limitările mai sus menţionate, o constituie trace-procesorul, adică un procesor superscalar având o memorie trace-cache (TC). Ca şi cache-urile de instrucţiuni (IC), TC este accesată cu adresa de început a noului bloc de instrucţiuni ce trebuie executat, în paralel cu IC. În caz de miss în TC, instrucţiunea va fi adusă din IC sau - în caz de miss şi aici - din memoria

195 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 197 principală. Spre deosebire însă de IC, TC memorează instrucţiuni contigue din punct de vedere al secvenţei lor de execuţie, în locaţii contigue de memorie. O linie din TC memorează un segment de instrucţiuni executate dinamic şi secvenţial în program (trace-segment). Evident, un trace poate conţine mai multe basic-block-uri (unităţi secvenţiale de program). Aşadar, o linie TC poate conţine N instrucţiuni sau M basic- block-uri, N>M, înscrise pe parcursul execuţiei lor. Figura Ansamblul trace-cache respectiv predictor multiplu Memoria TC este accesată cu adresa de început a basic-block-ului A, în paralel cu predictorul multiplu de salturi (vezi figura 4.19). Acesta, spre deosebire de un predictor simplu, predicţionează nu doar adresa de început a următorului basic- block ce trebuie executat ci toate cele (M-1) adrese de început aferente următoarelor (M-1) basic- block-uri care urmează după A. Cei (M-1) biţi generaţi de către predictorul multiplu (taken/ not taken) selectează spre logica de execuţie doar acele blocuri din linia TC care sunt predicţionate că se vor executa ( în cazul acesta doar blocurile A şi B întrucât predictorul a selectat blocurile ABD că se vor executa, în timp ce în linia TC erau memorate blocurile ABC). O linie din TC conţine:

196 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore N instrucţiuni în formă decodificată, fiecare având specificat blocul căreia îi aparţine. - cele 2 M-1 posibile adrese destinaţie aferente celor M blocuri stocate în linia TC. - un câmp care codifică numărul şi "direcţiile" salturilor memorate în linia TC. Înainte de a fi memorate în TC, instrucţiunile pot fi predecodificate în scopul înscrierii în TC a unor informaţii legate de dependenţele de date ce caracterizează instrucţiunile din linia TC curentă. Aceste informaţii vor facilita procese precum bypassing-ul datelor între unităţile de execuţie, redenumirea dinamică a regiştrilor cauzatori de dependenţe WAR (Write After Read) sau WAW (Write After Write) între instrucţiuni, etc., utile în vederea procesării Out of Order a instrucţiunilor. O linie din TC poate avea diferite grade de asociativitate în sensul în care ea poate conţine mai multe pattern-uri de blocuri, toate având desigur aceeaşi adresă de început (A), ca în figura Figura Selecţia dintr-o linie trace-cache asociativă Aşadar, segmentele începând de la aceeaşi adresă (A), sunt memorate în aceeaşi linie asociativă din TC. Ca şi în structurile TC neasociative, verificarea validităţii liniei selectate se face prin compararea (căutarea) după tag. Deosebirea de esenţă constă în faptul că aici este necesară selectarea - în conformitate cu pattern-ul generat de către predictorul multiplu - trace-ului cel mai lung dintre cele conţinute în linia respectivă. Este posibil ca această

197 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 199 selecţie complexă să dureze mai mult decât în cazul neasociativ şi prin urmare să se repercuteze negativ asupra duratei procesului de aducere a instrucţiunilor (fetch). Avantajul principal însă, după cum se observă şi în figură, constă în faptul că este probabil să se furnizeze procesorului un număr de blocuri "mai lung" decât un TC simplu. Astfel de exemplu, dacă pattern-ul real de blocuri executate este ABD, structura TC îl va furniza fără probleme, în schimb o structură TC neasociativă ce conţine doar pattern-ul ABC, evident va furniza în această situaţie doar blocurile AB. Pe măsură ce un grup de instrucţiuni este procesat, el este încărcat într-o aşa-numită "fill unit" (FU-unitate de pregătire). Rolul FU este de a asambla instrucţiunile dinamice, pe măsură ce acestea sunt executate, întrun trace-segment. Segmentele astfel obţinute sunt memorate în TC. După cum am mai subliniat, este posibil ca înainte de scrierea segmentului în TC, FU să analizeze instrucţiunile din cadrul unui segment spre a marca explicit dependenţele dintre ele. Acest lucru va uşura mai apoi lansarea în execuţie a acestor instrucţiuni întrucât ele vor fi aduse din TC şi introduse direct în staţiile de rezervare aferente unităţilor funcţionale. Unitatea FU se ocupă deci de colectarea instrucţiunilor lansate în execuţie, asamblarea lor într-un grup de N instrucţiuni (sau M blocuri) şi înscrierea unui asemenea grup întro anumită linie din TC. Există desigur cazuri când FU poate crea copii multiple ale unor blocuri în TC. Această redundanţă informaţională poate implica degradări ale performanţei, dar pe de altă parte, lipsa redundanţei ar degrada valoarea ratei de fetch a instrucţiunilor deci şi performanţa globală. Figura Segmente asamblate pe timpul execuţiei unei bucle de program

198 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 200 Se poate deci afirma că un TC exploatează reutilizarea eficientă a secvenţelor dinamice de instrucţiuni, reprocesate frecvent în baza a 2 motive de principiu: localizarea temporală a trace-ului şi respectiv comportarea predictibilă a salturilor în virtutea comportării lor anterioare. Aşadar, TC memorează trace-uri în scopul eficientizării execuţiei programului şi nu doar în scopul eficientizării procesului de aducere al instrucţiunilor. Aceasta, pe motiv că un segment din trace conţine numai instrucţiuni care se vor executa. În cazul IC, dacă într-un bloc există o ramificaţie efectivă, instrucţiunile următoare se aduceau inutil întrucât nu s-ar fi executat. Cum TC trebuie să lucreze într-o strânsă dependenţă cu predictorul de salturi, se impune îmbunătăţirea performanţelor acestor predictoare. Se pare că soluţia de viitor va consta într-un predictor multiplu de salturi, al cărui rol principal constă în predicţia simultană a următoarelor (M-1) salturi asociate celor maximum M blocuri stocabile în linia TC. De exemplu, pentru a predicţiona simultan 3 salturi printr-o schemă de predicţie corelată pe 2 nivele, trebuie expandată fiecare intrare din structura de predicţie PHT (Pattern History Table), de la un singur numărător saturat pe 2 biţi, la 7 astfel de automate de predicţie, ca în figura Astfel, predicţia generată de către primul predictor (taken / not taken) va multiplexa rezultatele celor 2 predictoare asociate celui de al doilea salt posibil a fi stocat în linia curentă din TC. Ambele predicţii aferente primelor 2 salturi vor selecta la rândul lor unul dintre cele 4 predictoare posibile pentru cel de-al treilea salt ce ar putea fi rezident în linia TC, predicţionându-se astfel simultan mai multe salturi. Dacă predictorul multiplu furnizează simultan mai multe PC-uri, TC rezolvă elegant şi problema aducerii simultane a instrucţiunilor pointate de aceste PC-uri, fără multiportarea pe care un cache convenţional ar fi implicat-o.

199 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 201 Figura Predictor a 3 salturi succesive Asemenea predictoare multiple în conjuncţie cu structuri de tip TC conduc practic la o nouă paradigmă a procesării unui program maşină numită "multiflow", caracterizată deci prin procesarea în paralel a mai multor basic-block-uri dintr-un program. În continuare se prezintă rezultatele unei cercetări bazată pe simulare asupra conceptelor novatoare de TC şi predictor multiplu, integrate într-o arhitectură superscalară extrem de agresivă dezvoltată la Universitatea din Michigan, SUA. În esenţă, investigaţia subliniază următoarele aspecte: -creşterea gradului de asociativitate a TC de la 0 (mapare directă) la 4 (asociativitate în blocuri de 4 intrări/ bloc) poate duce la creşteri ale ratei medii de procesare a instrucţiunilor de până la 15% -capacităţi egale ale TC şi respectiv memoriei cache de instrucţiuni (64 ko, 128 ko) conduc la performanţe cvasioptimale -asociativitatea liniei TC nu pare a conduce la creşteri spectaculoase de performanţă -performanţa globală faţă de o arhitectură echivalentă, dar fără TC, creşte cu circa 24%, iar rata de fetch a instrucţiunilor a instrucţiunilor în medie cu 92% În continuare se prezintă o altă tehnică de procesare, legată tot de reutilizarea dinamică a instrucţiunilor deja executate, posibil a fi folosită în conjuncţie cu un trace cache. Principalul scop urmărit constă în paralelizarea execuţiei unor instrucţiuni dependente RAW, bazat pe predicţia valorilor

200 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 202 regiştrilor utilizaţi de aceste instrucţiuni. Ideea originară aparţine şcolii de arhitectura calculatoarelor de la Universitatea din Wisconsin Madison, mai precis cercetătorilor A. Sodani şi G. Sohi care au introdus în 1997, la conferinţa ISCA 97 ţinută la Denver, SUA, conceptul de reutilizare dinamică a instrucţiunilor. Autorii arată în primul rând că reutilizarea unor instrucţiuni sau secvenţe de instrucţiuni este relativ frecventă şi se datorează modului compact de scriere al programelor precum şi caracteristicilor intrinseci ale structurilor de date prelucrate. Ideea de bază este că dacă o secvenţă de instrucţiuni se reia în acelaşi context de intrare, atunci execuţia sa nu mai are sens fiind suficientă o simplă actualizare a contextului de ieşire, în concordanţă cu cel precedent. Dacă arhitectura TC - după cum am arătat - acţionează asupra depăşirii unei limitări fundamentale asupra ratei de fetch a instrucţiunilor, această nouă inovaţie arhitecturală va acţiona asupra limitării ratei de execuţie a instrucţiunilor. Reamintim că această rată de execuţie este fundamental limitată de hazardurile structurale implicate precum şi de hazardurile RAW între instrucţiuni. Aşadar, instrucţiunile reutilizate nu se vor mai executa din nou, ci pur şi simplu contextul procesorului va fi actualizat în conformitate cu acţiunea acestor instrucţiuni, bazat pe istoria lor memorată. În vederea scopului propus, pe parcursul procesării instrucţiunilor, se construiesc în mod dinamic aşa-numite seturi de instrucţiuni. O instrucţiune "i" se adaugă unui set notat cu S dacă "i" depinde RAW de cel puţin una dintre instrucţiunile setului S. În caz contrar, instrucţiunea "i" va fi prima aparţinând unui nou set. Practic, construcţia acestor seturi implică generarea grafului dependenţelor de date ataşat programului, ca în secvenţa de mai jos (vezi figura 4.23). Figura Construcţia seturilor în vederea reutilizării codurilor

201 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 203 După procesarea instrucţiunilor, seturile rezultate sunt înscrise în vederea reutilizării într-un buffer special numit TDIS (Table of Dependent Instruction Sequences). O intrare în TDIS conţine 3 părţi principale: - partea IN, care memorează valorile operanzilor de intrare, adică aceia neproduşi prin secvenţa respectivă ci preluaţi din afara acesteia. - partea INSTRUCTION, conţine adresele instrucţiunilor inserate în seturi. - partea OUT, ce conţine numele regiştrilor destinaţie aferenţi unui set, precum şi valorile acestora. Pentru exemplificare, secvenţa de program anterioară necesită un buffer TDIS cu două intrări, ca mai jos (figura 4.24). Figura Structura TDIS la un moment dat Aşadar, la fiecare aducere a unei noi instrucţiuni, PC-ul acesteia se compară cu adresa primei instrucţiuni din fiecare linie a TDIS. Apoi, conţinutul actual al regiştrilor procesorului este comparat cu cel al părţii IN a TDIS. În caz de hit, secvenţa de instrucţiuni din TDIS poate fi reutilizată cu succes şi cu eludarea tuturor hazardurilor RAW dintre aceste instrucţiuni. Execuţia acestor instrucţiuni va însemna doar actualizarea contextului procesorului în conformitate cu valorile OUT din TDIS. Prin urmare, reutilizarea instrucţiunilor prin acest mecanism va avea un efect benefic asupra timpului de procesare al instrucţiunilor. Considerând un procesor superscalar care poate aduce, decodifica şi executa maximum 4 instrucţiuni / ciclu, secvenţa anterioară se procesează ca în cele două figuri următoare (4.25, 4.26).

202 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 204 Figura Execuţia programului pe un procesor superscalar Figura Execuţia programului pe un procesor cu reutilizarea codurilor Se observă că bufferul TDIS determină execuţia secvenţei prin reutilizarea instrucţiunilor în doar 4 cicli faţă de 7 cicli câţi ar fi fost necesari în cazul unei procesări clasice. Dacă lărgimea de bandă a decodorului de instrucţiuni ar fi fost de 6 instrucţiuni în loc de 4, execuţia secvenţei s-ar fi redus la doar 3 cicli. Teste efectuate pe benchmark-urile SPEC 95, au arătat că între 17% şi 26% dintre instrucţiunile acestor programe au putut fi reluate cu succes. Conceptul TDIS este eficient întrucât ca şi în cazul utilizării instrucţiunilor combinate, se elimină necesitatea secvenţierii în execuţie a unor instrucţiuni dependente RAW. Mai mult, în opinia autorului, dintr-un anume punct de vedere, conceptul reutilizării dinamice a secvenţelor dependente de instrucţiuni, violează oarecum celebra lege a lui G. Amdahl întrucât trece peste secvenţialitatea intrinsecă a programului şi procesează agresiv paralel chiar şi în acest caz, prin updating. Este fără îndoială posibil ca acest concept să se cupleze favorabil cu cel de tip "trace cache" anterior prezentat şi care acţionează favorabil în special asupra limitărilor ratei de fetch a instrucţiunilor.

203 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 205 În contextul următoarei generaţii arhitecturale de microprocesoare de înaltă performanţă, cea de a 4-a, se întrevede de asemenea implementarea unor mecanisme de aducere de tip Out of Order a instrucţiunilor, în plus faţă de cele deja existente în execuţia instrucţiunilor. Astfel de exemplu, în cazul unei ramificaţii dificil de predicţionat, pe durata procesului de predicţie, procesorul poate să aducă anticipat instrucţiunile situate începând cu punctul de convergenţă al ramurilor de salt. Aceste instrucţiuni fiind independente de condiţia de salt, pot fi chiar lansate în execuţie. Când predicţia se va fi realizat sau pur şi simplu când adresa destinaţie a ramificaţiei va fi cunoscută, procesorul va relua aducerea instrucţiunilor de la adresa destinaţie a ramificaţiei. În viitorul apropiat, unitatea de execuţie va trebui să lanseze spre unităţile funcţionale între 16 şi 32 instrucţiuni în fiecare tact. Evident, execuţia instrucţiunilor se va face Out of Order, pe baza dezvoltării unor algoritmi de tip Tomasulo. Staţiile de rezervare aferente unităţilor de execuţie, vor trebui să aibă capacităţi de peste 2000 de instrucţiuni Pentru a evita falsele dependenţe de date (WAR, WAW), procesoarele vor avea mecanisme de redenumire dinamică a regiştrilor logici. Desigur, tehnicile de scheduling static vor trebui îmbunătăţite radical pentru a putea oferi acestor structuri hardware complexe suficient paralelism Se estimează atingerea unor rate medii de procesare de instr. / tact, considerând că se pot lansa în execuţie maximum 32 instr. / tact. La ora actuală, cele mai avansate procesoare, cu un potenţial teoretic de 6 instr. / tact, ating în realitate doar instr. / tact. Aceste rate mari de procesare, impun execuţia paralelă a cca. 8 instrucţiuni Load/ Store. Aceasta implică un cache de date primar de tip multiport şi unul secundar, de capacitate mai mare dar cu porturi mai puţine. Miss-urile pe primul nivel, vor accesa al 2-lea nivel. Pentru a nu afecta perioada de tact a procesorului, este posibil ca memoria cache din primul nivel să fie multiplicată fizic. De asemenea, în vederea îmbunătăţirii performanţei, viitoarele microprocesoare vor predicţiona adresele de acces ale instrucţiunilor Load, asemenea predicţiilor salturilor, permiţând acestora să se execute înainte de calculul adresei. Aceste noi arhitecturi, care execută trace-uri ca unităţi de procesare, vor putea permite procesarea mai multor asemenea trace-uri la un moment dat, ceea ce conduce la conceptul de procesor multithreading. Aşadar paralelismul la nivel de instrucţiuni (ILP- Instruction Level Parallelism) va fi înlocuit cu unul mai masiv, constituit la nivelul thread-urilor unei aplicaţii (TLP- Thread Level Parallelism). În acest scop, arhitectura va trebui să conţină mai multe unităţi de procesare a trace-urilor, interconectate. La aceasta, se adaugă o unitate de control "high-level", în vederea partiţionării

204 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 206 programului în thread-uri de instrucţiuni independente. Se poate ajunge astfel la o rată de procesare de mai multe trace-uri / tact faţă de instrucţiuni / tact, metrica de performanţă obişnuită a procesoarelor superscalare actuale. E posibil ca aceste TLP-uri să acopere "semantic-gap"-ul existent între paralelismul la nivel de instrucţiuni şi respectiv cel situat la nivelul programelor, mult mai masiv. O altă paradigmă nouă, oarecum asemănătoare, dar mai îndepărtată probabil ca realitate comercială, o constituie multiprocesoarele integrate într-un singur circuit, ca soluţie în vederea exploatării paralelismului masiv ("coarse grain parallelism"). Aceasta este încurajată şi de anumite limitări tehnologice care ar putea afecta dezvoltarea arhitecturilor uniprocesor. Se estimează ca toate aceste idei arhitecturale agresive, să poată fi implementate într-un microprocesor real, abia atunci când tehnologia va permite integrarea "on-chip" a 800 milioane -1 miliard de tranzistori, ceea ce va fi posibil în jurul anului 2010 (predicţie "Semiconductor Industry Association" în 1996). La acest nivel de dezvoltare tehnologică va fi posibilă de asemenea integrarea "on-chip" a memoriei DRAM, la un timp de acces de cca. 20 ns. Ideea este atrăgătoare pentru că la aceeaşi suprafaţă de integrare, o memorie DRAM poate stoca de cca de ori mai multă informaţie decât o memorie SRAM pe post de cache. Se estimează că într-o primă fază, un DRAM integrat de 96 MB va necesita 800 milioane de tranzistori ocupând cca 25% din suprafaţa circuitului (vezi pentru detalii În orice caz, se pare că pentru a continua şi în viitor creşterea exponenţială a performanţei microprocesoarelor, sunt necesare idei noi, revoluţionare chiar, pentru că în fond paradigma actuală este, conceptual, veche de circa de ani. Ar fi poate necesară o abordare integrată, care să îmbine eficient tehnicile de scheduling software cu cele dinamice, de procesare hardware. În prezent, după cum a rezultat din cele prezentate până acum, separarea între cele 2 abordări este poate prea accentuată. În acest sens, programele ar trebui să expliciteze paralelismul intrinsec într-un mod mai clar. Cercetarea algoritmilor ar trebui să ţină seama cumva şi de concepte precum, de exemplu, cel de cache, în vederea exploatării localităţilor spaţiale ale datelor prin chiar algoritmul respectiv. Cunoaştem puţine lucruri despre ce se întâmplă cu un algoritm când avem implementate ierarhii de memorii pe maşina fizică. Desigur, asta nu înseamnă că programatorul va trebui să devină expert în arhitectura computerelor, dar nu o va mai putea neglija total dacă va dori performanţă. În noua eră post PC spre care ne îndreptăm, centrată pe Internet, fiabilitatea, disponibilitatea şi scalabilitatea vor trebui să devină criterii esenţiale alături de performanţa în

205 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 207 sine, ceea ce implică iarăşi necesitatea unei noi viziuni pentru arhitectul de computere. De asemenea, se poate predicţiona o dezvoltare puternică în continuare a procesoarelor multimedia. Aplicaţiile multimedia spre deosebire de cele de uz general, nu impun în mod necesar complicate arhitecturi de tip superscalar sau VLIW. Aceste aplicaţii sunt caracterizate de următoalele aspecte care le vor influenţa în mod direct arhitectura: -structuri de date regulate, de tip vectorial, cu tendinţe de procesare identică a scalarilor componenţi, care impun caracteristici de tip SIMD (Single Instruction Multiple Data), de natură vectorială deci, a acestor procesoare; -necesitatea procesării şi generării răspunsurilor în timp real; -exploatarea paralelismului la nivelul thread-urilor independente ale aplicaţiei (codări / decodări audio, video, etc); -localizare pronunţată a instrucţiunilor prin existenţa unor mici bucle de program şi nuclee de execuţie care domină timpul global de procesare. Având în vedere cele expuse anterior, în următorul paragraf se prezintă succint caracteristicile procesării vectoriale, cea care stă la baza acestor procesoare multimedia şi a altor procesoare şi coprocesoare specializate PROCESAREA VECTORIALĂ Alături de procesarea pipeline, procesarea vectorială este o tehnică deosebit de performantă nelipsită în implementarea procesoarelor componente ale supercalculatoarelor actuale. În esenţă procesarea vectorială reprezintă prelucrarea informaţiei numerice sub formă de vectori. Ca şi tehnica pipeline pe care o înglobează, procesarea vectorială urmăreşte în principiu creşterea ratei de procesare la nivelul programului, fiind deci o tehnică de exploatare a paralelismului la nivelul datelor din program. De multe ori aceste arhitecturi vectoriale se întâlnesc în literatură sub numele de sisteme SIMD (Single Instruction Multiple Data). În continuare se vor prezenta pe scurt câteva elemente arhitecturale specifice acestui concept precum şi problemele implicate de către acestea. se va insista ca şi până acum, pe problemele interfeţei hardware-software, necesare înţelegerii acestor arhitecturi de către utilizator în vederea exploatării lor prin software. Dacă precedentele modele nu afectau viziunea programatorului HLL,

206 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 208 modelul vectorial modifică acesastă viziune "independentă de maşină" întrun mod agresiv, similar cu cel al sistemelor multiprocesor. Prin noţiunea de vector se înţelege un tablou (şir) constituit din elemente scalare de acelaşi tip. În general elementele vectorilor sunt numere reprezentate în virgulă mobilă (semn, mantisă, caracteristică) pe mai mulţi octeţi (de regulă pe 4, 8 sau 10 octeţi conform standardelor IEEE). Prin lungimea vectorului înţelegem numărul de elemente scalare ce formează vectorul. După cum vom arăta, eficienţa maximă a procesării se obţine atunci când numărul unităţilor de prelucrare din cadrul unităţilor de execuţie specializate, coincide cu lungimea vectorului. O altă caracteristică a unui vector îl constituie pasul vectorului, adică diferenţa numerică dintre valorile adreselor de memorie la care se află două elemente scalare succesive din punct de vedere logic (V(i), V(i+1)) ale unui vector. În fine, lungimea scalarului, adică lungimea în octeţi a unui element scalar inclus în vector, are importanţă întrucât afectează performanţa unităţilor scalare de execuţie. În conformitate cu tipul operanzilor pe care îi prelucrează şi respectiv cu tipul rezultatului pe care îl generează se obişnuieşte clasificarea instrucţiunilor vectoriale (I), în patru categorii de bază şi anume: - instrucţiuni de tipul I1: V -> V, V= mulţimea operanzilor vectori. De exemplu, o instrucţiune de complementare a unui vector. - instrucţiuni de tipul I2 : V -> S, S= mulţimea operanzilor scalari. De exemplu, determinarea elementului scalar minim / maxim al unui vector. - instrucţiuni de tipul I3 : VxV -> V, de exemplu instrucţiuni aritmetico / logice cu 2 operanzi vectori - instrucţiuni de tipul I4 : VxS -> V, de exemplu înmulţirea unui vector cu un scalar. De remarcat că o singură instrucţiune vectorială specifică o multitudine de operaţii scalare executate în paralel, fiind deci echivalentă cu o buclă de program executată de un procesor scalar. Întrucât o buclă de instrucţiuni scalare poate fi înlocuită cu o singură instrucţiune vectorială, rezultă ca astfel se elimină multe dintre problemele generate de hazardurile specifice arhitecturilor pipeline (RAW-uri, ramificaţii, analiză antialias, etc.). O altă caracteristică a maşinilor vectoriale constă în faptul că acestea pipelinizează procesarea pe elemente scalare ale vectorilor. De asemenea nu este greu de sesizat, că procesarea vectorilor implică arhitecturi de memorie cu acces întreţesut ("interleaving"), ceea ce implică avantajul că latenţa memoriei va afecta la nivel de operare vector şi nu de operare scalar. O astfel de arhitectură este performantă de exemplu atunci când se citesc mai multe cuvinte succesive (situate în blocuri de memorie succesive), începând cu o adresă putere a lui 2. Întrucât operează asupra vectorilor compuşi din scalari reprezentaţi în virgulă mobilă, performanţa absolută maşinilor

207 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 209 vectoriale se exprimă în general în MFLOPS (Mega FLotant Operation Per Second), spre deosebire de perfomanţa procesoarelor scalare exprimată uzual în MIPS (Mega Instruction Per Second). Figura Structura unei maşini vector - registru Există maşini vectoriale de tip vector - registru şi respectiv memorie - memorie. Maşinile vector - registru au caracteristic faptul că toate operaţiile cu vectori, mai puţin cele de LOAD / STORE, se execută între regiştrii vectoriali interni. Aceste maşini, reprezintă deci o arhitectură analoagă arhitecturii LOAD / STORE din cadrul procesoarelor MEM. Maşinile memorie - memorie, mai puţin frecvente decât primele, se caracterizează prin faptul că toate operaţiile între vectori se execută memorie - memorie. O arhitectură vectorială tipică este prezentată în figura Regiştrii vectoriali sunt de lungime fixă notată cu M, fiecare registru conţinând un singur vector. Unităţile funcţionale, sunt unităţi de execuţie pipeline-izate care operează concurent asupra operanzilor vectori. Numărul de astfel de unităţi este diferit de la un procesor la altul. Evident că este necesară şi o unitate de control specială pentru detecţia şi controlul hazardurilor din cadrul unităţilor de execuţie pipeline. Unitatea LOAD / STORE, accesează vectorii din memoria principală. Se urmăreşte atingerea unei rate de transfer CPU memorie de un element / ciclu CPU, după depăşirea latenţei iniţiale a memoriei principale cu acces întreţesut. În fine, mai există şi setul de regiştri scalari, necesari pentru execuţia proceselor scalare. Probleme în vectorizarea programelor.

208 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 210 Prin noţiunea de vectorizare a unui program scris într-un limbaj de nivel înalt, se înţelege posibilitatea ca respectivul program să fie compilat utilizându-se instrucţiuni maşină vectoriale. Cum instrucţiunile se pretează în general în compilarea buclelor de programe scrise în limbaje de nivel înalt, se pune indeosebi problema vectorizării buclelor de program. Aşadar, pentru ca o maşină vectorială să fie viabilă, trebuie ca programul compilator să recunoască dacă o buclă de program este sau nu vectorizabilă şi dacă este atunci să genereze codul obiect corespunzător. Este evident că există bucle de program nevectorizabile, de ex. buclele recurente, precum secvenţa de mai jos : for i = 1 to 100 X(i+1) = X(i) + X (i+1); Se pune deci problema, cum poate detecta compilatorul dacă o buclă de program este ori nu este vectorizabilă? Dintre multele posibile răspunsuri la această problemă, în continuare prezentăm doar unul, deosebit de simplu. Prin urmare, există o dependenţă de date care face o buclă nevectorizabilă dacă există 2 indici de iteraţii j şi k în limitele buclei aşa încât se scrie un element cu indicele (a*j+b) într-un vector şi apoi se citeşte acelaşi element din vector, de astă dată cu indicele (c*k+d), unde a, b, c, d aparţin lui Z. Altfel spus, o buclă este nevectorizabilă dacă c.m.m.d.c. (a, c) divide (b - d). Prin prisma acestui criteriu de ex., rezultă imediat că bucla de mai jos este vectorizabilă (2 nu divide 3): for i = 1 to 100 X(4i+3) = X(2i) + Y(i); Lungimea fizică a regiştrilor vectori este fixă şi deci fatalmente limitată (<=M). De multe ori în soft se lucrează cu vectori de lungime mai mare decât M (lungimea regiştrilor vectori) sau se lucrează cu vectori de lungime necunoscută în momentul compilării, ca în exemplul buclei SAXPY (Single Precision A*X+Y) de mai jos: for i = 1 to n Y(i) = a * X(i) + Y(i); În astfel de cazuri, bucla se rescrie utilizând tehnica "strip mining", care reprezintă o tehnică ce permite generarea de cod program în urma compilării astfel încât fiecare operaţie vectorială să se efectueze cu vectori de lungime mai mică decât M. În urma aplicării acestei tehnici, bucla SAXPY devine : start = 1 lungvec = (n mod M) ; for j = 0 to (n / M) do ; întreg trunchiat for i = start, start + lungvec -1 do Y(i) = a * X(i ) + Y(i);

209 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 211 enddo start = start + lungvec; lungvec = M; enddo De remarcat că în prima iteraţie (j = 0) se operează pe vectori de lungime (n mod M) iar în celelalte iteraţii (j = 1, 2,...) se operează asupra unor vectori de lungime maximă admisă M. Rezultă deci că ar fi necesară o resursă specială (registru) care să controleze lungimea vectorilor asupra cărora se operează la un moment dat. Să considerăm acum o secvenţă de program destinată înmulţirii a două matrici A = B x C, de ordinul (100x100), ca mai jos. for i = 1 to 100 do for j = 1 to 100 do A(i,j) = 0 for k = 1 to 100 do A(i,j) = A(i,j) + B(i,k) * C(k,j) enddo enddo enddo Figura Moduri de memorare ale matricilor în memorie După cum se ştie, există două moduri de memorare a unei matrici în memoria principală : modul "row major" şi respectiv modul "column major" ca în figura anterioară. În cazul buclei de program anterioare, în ipoteza memorării matricilor după legea "column major", rezultă pas//c//=1 şi pas//b//=100. În ipoteza memorării după cealaltă lege, ar rezulta pas//c//=100 şi pas//b//=1. Oricum, rezultă clar necesitatea unor instrucţiuni de încărcare / memorare care pe lîngă adresa de bază şi lungimea vectorului să aibă ca parametru şi pasul acestuia. Vectorii cu pasul diferit de 1 cauzează complicaţii în accesul la memoria întreţesută. Pentru exemplificare să considerăm 16 module de memorie cu acces întreţesut având timpul de acces ta. Timpul necesar pentru a încărca un vector cu 64 elemente având pasul 1 este (4Tciclu + 4ta) unde Tciclu = durata unui ciclu din structura pipeline a procesorului vectorial. La cealaltă extremă, timpul necesar pentru a încărca un vector de aceeaşi lungime având însă pasul 32 este (64Tciclu + 64ta), deci mult mai mare. Pentru eliminarea problemelor implicate de pasul vectorului (latenţa mare a

210 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 212 memoriei pentru pasul diferit de 1) se cunosc mai multe soluţii bazate pe îmbunătăţirea arhitecturilor de memorii întreţesute. De exemplu, o matrice de 8 x 8 poate fi memorată în 8 blocuri de memorie cu acces întreţesut ca în figura Figura Memorarea unei matrici într-o memorie cu acces întreţesut Se observă că pasul unui vector "rând" este 1, iar pasul unui vector "coloană" este 9. Cum 2 elemente succesive ale unei coloane se află memorate în module succesive de memorie, printr-o proiectare adecvată a adresării modulelor bazat pe pasul vectorului accesat, se poate obţine în acest caz o accesare optimală a vectorilor "coloane" (la fel de rapidă ca şi accesarea unui vector "rând" care are pasul =1). În general dacă pasul vectorului este relativ prim cu numărul de module de memorie, se pot elimina latenţele ridicate prin organizări similare. Datorită frecvenţei accesării în cazul unor algoritmi numerici diverşi a vectorilor diagonali, se impune şi optimizarea accesului la aceşti vectori. Dacă numărul modulelor de memorie este o putere a lui 2, nu poate fi optimizat simultan accesul la vectorii coloană şi respectiv la cei diagonali. În acest caz se utilizează p module de memorie, unde p este un număr prim. O asemenea arhitectură de memorie este implementată în cazul supercomputerului BSP (Burroughs Scientific Processor - compania Unisys). În figura de mai jos (4.30) se prezintă o astfel de structură cu 5 module, având memorată o matrice de 4x4. Pasul vectorilor rând este 1, cel al vectorilor coloană este 6 iar cel al vectorilor diagonali este 7. De remarcat că accesul optimizat simultan la cele trei tipuri de vectori este posibil datorită faptului că numărul de module al memoriei (5) este relativ prim cu paşii vectorilor (1, 6, 7). În acest caz, alinierea ar fi fost efectivă dacă s-ar fi accesat de exemplu vectorul diagonal Evident că selecţia elementelor, citirea şi alinierea se fac comandate de un automat, în baza adresei de bază, lungimii şi pasului vectorului accesat (citit în acest caz).

211 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 213 Figura Optimizarea memorării vectorilor linie, coloană şi diagonali Să considerăm acum o arhitectură vectorială de tip SIMD (Single Instruction Multiple Data) ca în figura Această arhitectură SIMD se mai numeşte şi procesor matricial deoarece este constituită din mai multe procesoare identice, relativ simple, care execută acelaşi program simultan, asupra unor date locale. Putem considera aceste structuri de calcul ca făcând trecerea la arhitecturile de tip MIMD (Multiple Instruction Multiple Data). Figura Arhitectură SIMD De precizat că o astfel de structură de calcul execută un singur program asupra mai multor operanzi scalari simultan (ALU-uri multiple) sau acelaşi program este executat în paralel de mai multe procesoare (UE) asupra propriilor seturi de date memorate în resursele locale. Nu intrăm aici în amănunte asupra topologiei şi caracteristicilor diverselor tipuri de reţele de interconectare, prin intermediul cărora se realizează schimbul de date între unităţile locale de execuţie, acestea sunt arhicunoscute şi prezentate în toate cărţile generale de arhitectura sistemelor de calcul. Să considerăm o aplicaţie care însumează de elemente pe un sistem SIMD având 128 unităţi de execuţie distincte. Pentru început, un procesor specializat de I/O (front computer) plasează câte un subset de 1000 de elemente în memoria locală a fiecărei unităţi de execuţie (UE). Apoi fiecare UE procesează câte o secvenţă de program astfel :

212 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 214 sum = 0; for (i = 0, i < 1000; i = i + 1) sum = sum + Al(i); Al(i) reprezintă o tabelă locală conţinând 1000 de scalari, câte una în fiecare UE. Rezultă la final faptul că fiecare dintre cele 128 de sume parţiale va fi situată în altă UE. Programul SIMD pentru însumarea sumelor parţiale distribuite ar fi: limit = 128; half = 128; repeat half = half/2 if(pn >= half && Pn < limit) send (Pn-half;sum); if(pn < half) sum = sum + receive( ); limit = half; until (half = = 1); Funcţia send(x,y) are parametrii x = adresă procesor destinaţie, y = variabilă emisă. Precizăm că am notat prin P n numărul unităţii de excuţie, deci P n {0, 1, 2,...,127}. Send / Receive sunt funcţii emisie / recepţie prin / din reţeaua de interconectare a unităţilor de execuţie aferente SIMD. Suma finală se va obţine în UE0. Timpul de execuţie este de ordinul O(log2N), unde N=numărul de UE spre deosebire de un sistem convenţional tip SISD care ar realiza adunarea sumelor parţiale într-un timp O(N). Secvenţa anterioară poate fi scrisă mai elegant, prin eliminarea variabilei half, ca mai jos limit = 128; repeat if(pn >= limit/2 && Pn < limit) send (Pn-limit/2;sum); if(pn < limit/2) sum = sum + receive( ); limit = limit/2; until (limit = = 1); Buclele condiţionate implică şi ele anumite cerinţe în procesarea vectorială. De exemplu să considerăm secvenţa următoare : for i = 1 to 100 do if(x(i) diferit de 0) then X(i) = X(i) + Y(i); endif enddo Pentru ca secvenţa să fie vectorizabilă rezultă necesitatea existenţei unui registru vector de mascare, de lungime egală cu lungimea regiştrilor vectori. Acest registru va conţine elemente pe '0' sau '1', în conformitate cu testul făcut asupra unui vector pe o anumită condiţie. Operaţiile vectoriale se

213 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 215 vor executa numai asupra acelor elemente din vector cărora le corespunde un element pe '1' în registrul de mascare. Considerând adresele de bază ale vectorilor X şi Y memorate în regiştrii Rx respectiv Ry, bucla anterioară este echivalentă cu următoarea secvenţă de instrucţiuni maşină vectorială : LV V1, Rx; V1<-MEM/Rx LV V2, Ry; V2<-MEM/Ry LD F0,#0; instr. scalară F0<-0 SNESV F0, V1; setează elementele reg. de mascare aferent elementelor V1(i) diferit de 0, i = ADDV V1, V1, V2; V1<- (V1)+(V2) SETVM; setează toate elementele reg. de mascare VM SV Rx, V1; V1 -> MEM/Rx Există bucle de program nevectorizabile datorate unor dependenţe de date "ascunse", generate de existenţa unor variabile scalare, ca mai jos : x = 0; for i = 1 to 100 do x = x + A(i) * B(i); enddo Această buclă nevectorizabilă se poate transforma în următoarea secvenţă semi-vectorizabilă, obţinută prin transformarea scalarului în vector şi care paralelizează 100 de înmulţiri care se executau serial în secvenţa anterioară : y = 0; for i = 1 to 100 do X(i) = A(i) * B(i); vectorizabil enddo for i = 1 to 100 do y = y + X(i); nevectorizabil enddo Multe dintre supercomputerele actuale reprezintă multiprocesoare formate din mai multe procesoare vectoriale care procesează în paralel, având deci un accentuat paralelism spaţial. În acest context să considerăm bucla de program : for i = 1 to n do X(i) = Y(i) + Z(i); (1) Y(i+3) = X(i + 4); (2) enddo Un compilator inteligent din cadrul unui sistem vectorial multiprocesor, trebuie să sesizeze potenţialul paralelism din cadrul acestei secvenţe precum şi dependenţele de date dintre relaţiile (1) şi (2). Secvenţa de mai jos va fi transformată astfel : for j=1 to n step 3 do

214 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 216 for i=j to j+2 doall X(i)= Y(i)+Z(i); (1') Y(i+3)=X(i+4) ; (2') enddoall enddo Se observă că s-au obţinut de fapt 2 bucle vectorizate, deci s-au eliminat dependenţele de date. Instrucţiunea "doall" determină execuţia paralelă, pe procesoare distincte, a secvenţelor (1') şi (2'), acum perfect vectorizabile şi independente. Desigur că generarea de cod vectorial sau cod vectorial-paralel prin intermediul unor compilatoare pe limbaje convenţionale, nu poate exploata optimal procesarea vectorială respectiv multiprocesarea vectorială. Actualmente, se lucrează intens, cu deosebire în Statele Unite ale Americii, pentru elaborarea de noi limbaje specifice programării vectoriale / concurente (IBM Parallel Fortran, Cedar Fortran, limbajul VPC - un supraset vectorial / concurent al limbajului C, etc.). Cert este că odată cu avansul tehnologiei VLSI, preţul acestor microprocesoare vectoriale va scădea şi ele vor pătrunde tot mai masiv pe piaţă. Încă din 1988 firma Ardent a realizat un CPU în jurul unui microprocesor RISC + un coprocesor vectorial integrat la preţul de numai 180$. Ca şi procesarea paralelă la nivelul instrucţiunilor, ea a produs un impact puternic atât asupra proiectării hardware cât şi asupra compilatoarelor. Oricum, dezvoltarea compilatoarelor reprezintă provocarea esenţială şi în aceste arhitecturi paralele. În concluzie, am prezentat câteva idei relative la procesarea vectorială întrucât reprezintă un concept arhitectural de referinţă în proiectarea unui procesor performant (MMX) chiar dacă nu intră strict în categoria arhitecturilor cu paralelism la nivelul instrucţiunilor care se abordează cu precădere în această lucrare.

215 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 217 Lecture Notes in Multiprocessors (LNM) - Draft - -Only for my students use- Acest document (LNM) este doar un document de lucru in cadrul procesului didactic desfasurat de autor. Este destinat exclusiv studentilor mei, in procesul de invatare During the period the microprocessors performance growth with an average rate of 52% per year. Since 2002 the improvement was less than 20% per year [Hen07]. In order to keep a significant performance growth, instead of scaling performance by improving single core performance, performance is scaled during the last years (INTEL, starting from 2004) by putting multiple cores on a single chip, effectively integrating a complete multiprocessor on one chip. Actually multicores are parallel computers, mainly exploiting thread and task level parallelisms. Some of the most important reasons that justify this sea change in computing (Paul Otellini, President, Intel, 2005) were the followings: o o o o Consumul de putere (Power wall) si disipatia termica; Dynamic power Pd=kCV 2 F Prapastia de comunicare procesor+memorie (Memory wall); Exploatarea ILP şi-a cam atins limitele (ILP wall); Memory wall + ILP wall + Power wall = Brick wall Performance = (Cores * F) Since the total performance of a multi-core is improved without increasing the clock frequency, multi-cores offer a better performance/watt ratio than a single core solution with similar performance.

216 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 218 Figura preluata din cartea autorilor Hennessy si Patterson [Hen07] (v. bibliografia) A parallel computer consists in a collection of computers (processing elements) that communicate and cooperate in order to run large (concurrent) applications fast. It extends the concepts used in uniprocessors with communication architecture (interconnection network) that allows processors to inter-communicate. Parallel computers usually exploit the advantage of using many small, inexpensive, low power processors [Cul99] but they could contain also heterogenous processors, including out of order superscalars or SMT (Simultaneous Multithreading) processors. Desirable attributes of multiprocessor systems: Scalabilty Fault tolerant Higher absolute performance (greater than a single processor) Performance Metrics for Parallel Computers: - Speedup (N processors) = Time (1 processor)/time (N processors) = Performance (N processors)/performance (1 processor) - Latency the time taken for an operation [seconds per operation]

217 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore Bandwidth the rate at which operations are performed [operations per second] - Cost/Complexity the impact that operations have on the execution time of the program. In other words, the latency times the number of operations performed. Ideal ar fi ca un SMM dotat cu N procesoare să proceseze un program de N ori mai rapid decât un sistem monoprocesor, cerinţă numită scalabilitate completă. În realitate, acest deziderat de scalabilitate nu se realizează, din multiple motive. În privinţa scalabilităţii, aceasta este mai uşor de realizat pe un sistem cu resurse distribuite decât pe unul având resurse centralizate, întrucât acestea din urmă constituie un factor de strangulare a activităţii. Dintre cauzele care stau în calea unei scalabilităţi ideale, se amintesc: 1. Gradul de secvenţialitate intrinsec al algoritmului executat. Aşa de exemplu, există în cadrul unui algoritm operaţii secvenţiale dependente de date şi deci imposibil de partajat în vederea procesării lor paralele pe mai multe procesoare. n = y + z; scalar secvential dependent de RAW 100% = secvenţial a = n + b; for i = 1to10 paralelizabil pe 10 procesoare A(i) = B(i) + C(i); (1-f) 100%=paralelizabil Accelerarea S (Speed-up) pentru un SMM cu N procesoare este prin definiţie: Ts S = T unde: T s = timpul de execuţie pentru cel mai rapid algoritm secvenţial care rezolvă problema pe un monoprocesor (SISD Single Instruction Single Data according to Flynn s taxonomy) T N = timpul de execuţie al algoritmului paralel executat pe un SMM cu N µprocesoare. Dacă notăm cu f = fracţia (procentajul, fractia-ratio) din algoritm care are un caracter eminamente secvenţial, f [0,1], putem scrie: N

218 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 220 T N = f T s (1 f) T + N s, adică S = f T s Ts (1 f) T + N s 1 sau: S = (1 f) 1 Legea lui (Eu)Gene Amdahl, 1 S N f + f N (scalabil) Legea lui G. Amdahl sugerează că un procentaj (fx100%) oricât de scăzut de calcule secvenţiale impune o limită superioară a accelerării (1/f) care poate fi obţinută pentru un anumit algoritm paralel pe un SMM, indiferent de numărul N al procesoarelor din sistem, de tipul acestora, de topologia de interconectare etc. Un f=0.2 S 5. Functia S(f) este hiperbolica. Motive acestei limitari semnificative de performanta sunt urmatoarele: 1. Timpul consumat cu sincronizarea şi comunicarea între procesele rezidente pe diversele (µ)procesoare din sistem. 2. Imposibilitatea balansării optimale a activităţii procesoarelor din system. Frecvent nu se poate evita situaţia în care anumite procesoare să fie practic inactive sau cu un grad scăzut de utilizare. 3. Planificarea sub-optimală din punct de vedere al performantei a proceselor d.p.d.v. software (activare proces, punere în aşteptare a unui proces, schimbarea contextului în comutarea proceselor etc.) 4. Operaţiile de I/O, în cazul nesuprapunerii lor peste activitatea de execuţie a task-ului de către procesor. Un parametru important care influenţează direct performanţa unui SMM, e dat de granularitatea algoritmului de executat, adică dimensiunea medie (număr de instrucţiuni, timp de execuţie etc.) a unei unităţi secvenţiale de program (USP). Prin USP se înţelege o secvenţă de program în cadrul algoritmului paralel în cadrul căreia nu se execută operaţii de sincronizare sau de comunicare date cu alte procese. Se mai defineşte şi un alt parametru, numit timp mediu de comunicaţie între 2 task-uri nerezidente pe acelaşi procesor.

219 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 221 MultiCore omogene vs. neomogene (exemplu preluat din cartea Hennessy si Patterson [Hen07]) Consideram un system multiprocessor cu 100 procesoare omogene simple care accelereaza corespunzator 90% din programul dynamic. Se considera ca 10% din codul dynamic este secvential. In acest caz, accelerarea este: S 1 (1 f) f + N = = 1 / ( /100) = 9.2 Accelerarea obţinută pe un sistem neomogen de complexitate echivalentă, având 90 de nuclee simple şi un nucleu complex (superscalar, SMT) care ar reduce la jumatate timpul de rulare al codului secvential, este superioară: S = 1 / (0.1/ /90) = 16.7 Din punct de vedere al raportului între granularitatea algoritmului (G) şi timpul de comunicaţie (C), se citează 2 tipuri de algoritmi: a. Coarse grain parallelism (paralelism intrinsec masiv), caracterizaţi de un raport G/C relativ mare. Aceşti algoritmi se pretează cu bune rezultate la procesoare pe sisteme paralele de tip SIMD (vectoriale, Single Instruction Multiple Data) sau MIMD (multiprocesoare, Multiple Instruction Multiple Data). b. Fine grain parallelism (paralelism intrinsec redus), caracterizaţi de un raport G/C relativ mic. În acest caz nu este recomandabilă multiprocesarea din cauza granularităţii fine a algoritmului şi a timpilor mari de comunicaţie/ sincronizare între procesoare (threads), elemente ce vor reduce dramatic accelerarea SMM. Se recomandă exploatarea paralelismului redus prin tehnici monoprocesor de tip Instruction Level Parallelism [Vin02]. O problemă majoră, practic deschisă la ora actuală, o constituie scrierea de software pentru SMM. Sarcina unui compilator SMM este dificilă întrucât trebuie să determine o metodă de a executa mai multe operaţii (programe), pe mai multe procesoare, în momentele de timp neprecizabile. Apoi, trebuie optimizat raportul G/C printr-o judicioasă partiţionare în general statică si dinamica a algoritmului de executat.

220 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 222 GRANULARITATE ŞI COMUNICARE. MODELE ANALITICE DE ESTIMARE A PERFORMANŢEI (paragraf facultativ!) 1. Un model pesimist Se consideră pentru început un sistem biprocesor care trebuie să execute un program (aplicaţie) ce conţine M task-uri. Se presupune că fiecare task se execută în "G" unităţi relative de timp şi că oricare 2 task-uri nerezidente pe acelaşi procesor consumă "C" unităţi relative de timp pentru intercomunicaţii (schimburi de date + sincronizări). Se va considera că "K" task-uri se vor executa pe un procesor iar (M-K) task-uri pe celălalt, ( ) k=1,2,...,m. Pesimismul modelului constă în faptul că se va considera că nu e posibilă nici o suprapunere între execuţia unui task şi comunicarea acestuia cu celelalte task-uri nerezidente pe acelaşi procesor. În acest caz, timpul de execuţie (ET) aferent aplicaţiei este dat de relaţia: ET = G Max(M K,K) + C (M K) K Particularizând pentru M=50. G/C=10 (granularitate "mică"), G=1 (un task se execută într-o singură unitate de timp), se obţine: ET = Max (50-K, K) K(50-K) The first term represents the effective processing time and the second one the interprocessors communication time. În acest caz rezultă K optim = 0, adică optim e ca toate cele 50 taskuri să ruleze pe un singur procesor (monoprocesare!). Dacă am considera granularitatea aplicaţiei G/C = 50 ("mare"), se va obţine: ET = Max (50-K, K) + K(50-K)/40 În acest caz K optim = M/2 = 25, adică o distribuire uniformă a numărului de task-uri pe cele 2 procesoare ("coarse grain parallelism"). În concluzie, pentru un sistem biprocesor în condiţiile date, strategia optimală în vederea obţinerii performanţei (ET) maxime este: G M a) Dacă Koptim = 0 (monoprocesare) C 2

221 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 223 b) Dacă 2 M C G > Koptim = M/2 (procesare paralelă omogenă) Generalizare pentru N procesoare Se consideră pentru început un SMM cu 3 procesoare P1, P2, P3, care are de executat o aplicaţie având M task-uri. Se presupune că P1 execută k1 task-uri, P2 execută k2 task-uri iar P3 execută k3 task-uri, k1+k2+k3=m. Figura. Ansambluri procesor - task Rezultă imediat că timpul de comunicaţii (ET c ) inter-task-uri va fi: ( ) ( ) ( ) [ ] ( ) = = = i i i c k M k C k k k k k k k k k C ET Prin urmare, pentru un sistem cu N procesoare avem: = + = N i i i i k M k C k Max G ET 1 ) ( 2 ) ( sau: N i k M C k Max G ET N i i i, 1 ) (, 2 ) ( = + = = În ipoteza - nu neapărat optimală - unei alocări uniforme a task-urilor pentru toate cele N procesoare, avem: = N M k i N M C M C N M G ET N = Timpul de execuţie al algoritmului pe un singur procesor este: ET 1 = G M

222 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 224 "Punctul critic" se atinge când ET N = ET 1, adică: În concluzie: a) Dacă b) Dacă 2 2 G M C M C M + = + G M, sau: N 2 2N 1 C M = 1 G 1 1, adică: N 2 N G M = (condiţie de performanţă identică mono-multi) C 2 G M C 2 G M < C 2 2. Un model mai "optimist", este indicată multiprocesare omogenă (coarse grain), monoprocesarea e mai indicată (fine grain) Să presupunem acum că execuţia task-urilor se poate suprapune cu comunicaţia interprocesoare. În acest caz avem: N C ET = Max G Max( ki ), k 2 i= 1 i ( M k ) Optimul s-ar obţine atunci când suprapunerea celor 2 componente ar fi perfectă, adică: 2 G M C M C M G C M 1 = = 1 N 2 2 2N N 2 N Pentru un număr "mare" de procesoare (N) avem: 2 i G N C M 2 N optim 2 = N G C Obs. 1. N creşte liniar cu granularitatea (G/C) aplicaţiei

223 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 225 Obs. 2. Aparent paradoxal, N optim este invers proporţional cu numărul de task-uri paralele M în care s-a împărţit aplicaţia. Actually it is not a paradox pentru că creşterea lui M, determină creşterea timpului de comunicaţii interprocesor (ET c ). 3. Un model cu costuri liniare de comunicaţie Să considerăm acum un model de SMM în care costurile de comunicaţie să fie liniare cu numărul de procesoare N şi nu cu numărul de task-uri asigurate fiecărui procesor (P i ), ca în modelul precedent. În acest caz, putem scrie: ETN = G Max( ki ) + C N Să determinăm în continuare, până la ce "N", avem ca ET N ET N+1, adică să determinăm în acest caz un număr optim de procesoare ( ETN =0 N opt ) care să proceseze cele M task-uri. Pentru simplificare, se consideră o distribuţie uniformă de taskuri/procesor k i =, adică: M N G M ET N = + C N N 1 1 ETN = ETN ETN = G M C N N + 1 G M G N( N + 1) ET N = C = 0 = N( N + 1) C M + Rezultă deci N optim G M. C 1 =0, adică: Aşadar N optim nu creşte proporţional cu numărul de task-uri M ci proporţional cu M şi de asemenea, proporţional cu rădăcina pătrată a G raportului. Pentru un N > Noptim, performanţa SMM cu costuri liniare C de comunicaţie, se degradează datorită costurilor comunicaţiilor interprocesor.

224 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 226 Obs. Toate aceste modele sunt simpliste, generând rezultate discutabile, chiar şi contradictorii. Complexitatea procesării SMM e prea mare pentru abordări analitice de referinţă. Pentru o adecvata evaluare si optimizare se impun şi aici simulările pe benchmark-uri concurente specifice. Specific applications for parallel systems Scientific computing containing a lot of numerical processing with a significant concurrency degree. Computational science and engineering problems: modeling global climate change, evolution of galaxies, the atomic structure of materials, the efficiency of combustion with an engine, the flow of air over vehicles surfaces, the damage due to impacts, decoding human genome, ocean circulation, fluid turbulence, computational fluid dynamics, superconductor modeling, computer vision, multimedia, signal processing, cryptography, voice processing, etc. Commercial computing. Computer system speed and capacity translate directly into the scale of business that can be supported by the system. OLTP (On-Line Transaction Processing) Benchmarks measures throughput in transactions per minute (tpm) on a typical workload. The LINPACK benchmark is the most used metric of performance on numerical applications (Millions of Floating Point Operations Per Second, MFLOPS). Other parallel benchs: PARSEC, SPLASH 2 etc. The programming model (PM) represents the conceptualization of the virtual machine that the programmer uses in coding applications. The PM specifies how parts of the program running in parallel communicate and what synchronizations are necessary to coordinate the global activity. Communication between processes occurs when data written by one process is read by another one. Therefore, a parallel PM represents a link between the programmer s concurrent application model and its implementation on the parallel concrete hardware architecture. Usually, the PM is independent by the number of processors. Further we ll present 2 important true parallel PMs or classes of parallel machines: Shared address it posts information at known shared locations. Individual activities can be coordinated by taking note of who is doing what task. An important aim is to cause multiple processors to execute different parts of a single program to complete it faster. Thus, processors will cooperatively and concurrently execute a parallel program. The cooperation and exchange of information among processors in shared memory architectures is done through the read/write of shared memory locations and through the use of synchronization, to control their access to shared variables. Cheia sincronizării proceselor în SMM este data de implementarea unor aşa-zise procese atomice. Un proces atomic reprezintă un proces care odată iniţiat, nu mai poate fi întrerupt de către un alt proces. Spre exemplu, să

225 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 227 considerăm ca pe un SMM se execută o aplicaţie care calculează o sumă globală prin nişte sume locale calculate pe fiecare procesor, ca mai jos: Proces atomic LocSum=0; for i=1 to Max LocSum=LocSum+LocTable[i]; secvenţa executată în paralel de ; către fiecare procesor! LOCK GlobSum=GlobSum+LocSum; sectiune critica, Read-Modify-Write UNLOCK Procesul LOCK/UNLOCK este atomic, în sensul că numai un anumit procesor poate executa acest process (thread) la un moment dat ( Make updates to a location appear atomic ). În caz contrar s-ar putea obţine rezultate hazardate pentru variabila globală "GlobSum". Astfel de exemplu, P1 citeşte GlobSum = X, P2 la fel, apoi P1 scrie GlobSum = GlobSum + LocSum1 iar apoi P2 va scrie GlobSum = GlobSum + LocSum2 = X + LocSum2 (incorect!). Este deci necesar ca structura hardware să poată asigura atomizarea unui proces software. O soluţie constă în implementarea în cadrul µprocesoarelor actuale a unor instrucţiuni atomice de tip "Read - Modify - Write", neinteruptibile la nivelul unei cereri de bus. Regiune critică (critical section) - desemneaza o secţiune de cod care poate fi controlată la un moment dat numai de către un singur proces. Message passing the information is send or received using messages, and these events orchestrate individual activities. Shared address architectures. Details All processors (cores) share a single global memory logical address space. The key property of shared memory multiprocessors is that communication occurs implicitly as a result of load/store conventional memory access instructions to shared variables. Each processor can name every physical location in the machine; a process can name all data it shares with others within its virtual address space. Synchronization is implemented via locks (hardware) or semaphores (software). A process (task) represents an instance of an active application (the dynamic execution sequence of a static program) having a virtual address space and one or more threads of control that share portions of that address space. This involves that those shared virtual address space portions are mapped to a common physical location. The OS allocates for each task memory and CPU resources. Usually shared variables have the same address and meaning in each thread. Process private segment typically contains the stack and private data (including code).

226 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 228 Threads are a way for a program to split itself into two or more simultaneously running sub-tasks (for example, subsets of the iterations of a common parallel loop). They are natural only in a concurrent programming paradigm. Threads are distinguished from multitasking operating system processes in that processes are typically independent, carry considerable state information, have separate data spaces, and interact only through system-provided inter-process communication mechanisms. Multiple threads, on the other hand, typically share the state information of a single process, and share memory and other resources directly. They may interact through the shared memory, and appropriate synchronization operations must control this interaction. A thread is atomic related to the OS and sequential. However, from the object code processing point of view the thread is not necessary sequential. Instruction Level parallelism could be exploited from a thread. Cooperation and coordination among threads is accomplished by reading (loads) and writing (stores) shared variables and pointers referring to shared addresses. Figura preluata din cartea [Cul99] (v. bibliografia) The shared address space programming model assumes one or more threads of control, each operating in an address (data) space that contains a region shared between (all) threads and may contain a region that is private for each thread. Esenţa principială a thread-ului este aceea că execută o procedură, în cadrul aceluiaşi proces, în paralel cu alte thread-uri. Contextul şi zonele de date ale procesului sunt utilizate în comun de către toate thread-urile componente. Contextul procesului conţine informaţiile de localizare în memoria internă şi informaţiile de stare aferente execuţiei procesului. Singurul spaţiu de memorie ocupat exclusiv de catre un thread este spaţiul de stivă. Fiecare

227 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 229 thread îşi întreţine propriul context, cu elemente comune contextului procesului părinte al thread-ului. Interconnection Networks (Network on Chip - NoC) Computer power increases by the square of the number of nodes on the network. (Robert Metcalf s Law) A typical centralized (global) shared memory multiprocessor scheme is presented below. The global memory might be physically distributed using many memory modules in order to exploit parallel transactions. Figura The shared memory multiprocessors have a general interconnection network between processors and memory. Any processor can access any memory location. Due to the Moore s law, in the last years the processors (cores) are interconnected within a single chip (computer), illustrating the Network on Chip (NoC) concept. Usually NoCs are fine grained and heterogeneous. In contrast, common networks are coarse grained (computers) and more homogeneous. The NoC s job is to transfer information to any source node to any desired destination node. Performance means: small latency and a large number of concurrent transfers. The NoC is composed of links and switches. A link is essentially a bundle of wires or fibers that carries an analog signal [Cul99]. Obviously, there are necessary digital to analog and analog to digital converters (transmitter receiver). Fiber optics transmits digital data as pulses of light (LED, laser diode). A full duplex connection requires two fibers. The diameter of the cable is limited to one wavelength of light. Fiber optics needs opticalelectrical and vice-versa conversions. The transmitter, link and receiver form a communication channel. The link level protocol segments the stream of symbols crossing a channel into logical units called messages or packets, useful for the routing algorithms. Thus, a message represents the information sent between processors through an interconnection network or a NoC. A switch consists of a set of input ports, a set of output

228 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 230 ports, an internal crossbar, internal buffering (FIFOs), and control logic to effect the input/output connection at each point in the time. The networks are classified in direct and indirect networks. In a direct network each node has two functions: data processing and communication. In an indirect network each node has only one function: data processing or data communication. In order to send/receive messages between two computers it is needed a so-called transfer protocol. For example, the following essential steps are necessary to send a message: Copy the data from the memory to a dedicated OS transmission buffer. The OS calculates a checksum of the useful data and includes it in the tail of the message. After this it starts a time-out timer. The OS send the message through the dedicated hardware-software components. The following essential steps are necessary to receive a message: The OS copies the message from the network interface to a dedicated reception FIFO buffer. If this buffer is full the receiver must transmit a corresponding message to the sender. The received checksum is compared with the calculated one. If the comparison is successful the receiver acknowledge to the sender through a special message. As a consequence, the sender will reset its timer. Otherwise, it deletes the received message and the sender will send it again when the time-out timer underflows (it restarts the timer). If the step 2 successfuly ends, the OS transfers the message to the memory (user s space). The header may contain the sequence number of the message (in order to permit correctly assemblation), routing information, etc. Some of the most important characteristics of an interconnection network are the followings: Întârzierea - Latency, adică timpul de transmitere pentru un singur cuvânt (mesaj) Lărgimea de bandă, adică ce trafic de mesaje poate suporta reţeaua în unitatea de timp. The bandwidth (throughput) represents the maximum rate at which the interconnection network (channel) can propagate the information (bits/second). Sender overhead (SO) represents the time for moving the message from the CPU s memory to the FIFO transmission buffer (before starting TF; see below). Time of flight (TF) the time for the first sent bit of the message to arrive to the receiver

229 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 231 Transmission time (TT) represents the period between when the first bit of the message arrives at the receiver and when the last bit of the message arrives at the receiver. Receiver overhead (RO) - represents the time for moving the message from the FIFO reception buffer to CPU s memory. Total network latency=so+tf+tt+ro Gradul de conectivitate, adică numărul de vecini direcţi pentru fiecare nod Costul hardware, adică ce fracţie din costul total al hardului reprezintă costul RIC Fiabilitatea şi funcţionalitatea (arbitrare, întreruperi). An interconnection network or a NoC is characterized by: The topology is determined by the physical interconnection structure of the network graph. It may be regular or irregular. The routing algorithm (RA) determines which routes messages may follow through the NoC s structure. A RA is non-adaptive if the route taken by a message is determined by its source and destination regardless of other traffic in the network; the packet will follow its path regardless of whether a link along the way is blocked. Minimal route could overload the network. As a consequence, many adaptive routing algorithms were developed. Adaptive RAs allow the route for a packet to be influenced by traffic it meets along the way. However, high congestion degree could involve some problems. Deadlock might occur when a packet waits for an event that cannot occur and therefore the packets can make no forward progress (example, the queues are full and each is waiting for another to make resources available). Sometimes we can have a kind of deadlock called indefinite postponement meaning that a packet waits for an event that can occur but never does. Livelock might occur when a packet never leads to its destination through the routing algorithm. Thus Deadlock Livelock but the reciprocal implication is not always true. The solution to congestion problems is to interdict new packets to enter in the NoC until the traffic reduces. The switching strategy determines how the data in a message traverses its route. Switching main aim consists in bandwidth improvement. It permits multiple pairs of nodes to simultaneously communicate. In circuit switching the path from the source to the destination is established and reserved until the message is transferred over the circuit. The alternative is packet switching in which the message is broken into a sequence of packets. A packet contains data, a header (destination, routing and sequencing information and control information) and a trailer (error checking code). Packet switching allows a better utilization of network resources because links and buffers are only occupied while a packet is traversing them. In the so called source-based routing the message statically contains the routing path. In the so called destination-based routing the message s header contains the destination address. In this case each switch must choose a

230 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 232 path in order to send further the message. Thus it is necessary a routing table lookup on every packet in order to decide how to route the packet. There are two main strategies: store-and-forward and cut-through routing or wormhole routing ([Cul99], pg. 757). In the store-and-forward case the switch waits for receiving the whole message before to send it to the next switch. Alternatively, in the cutthrough routing case, the message is pipelined through the sequence of switches belonging to the routing path. Therefore, cut-through strategy achieves lower latency by choosing the routing path on the first flit (flow control units, dividing a packet), called head flit, from the message. The tail flit will release the path (channel) reservation. Also it reduces buffering overhead comparing with storeand-forward. Unfortunately it increases the message blocking probability especially under high traffic conditions. The control flow mechanism determines when the packet moves along its route. It is necessary whenever two or more messages attempt to use the same network resource at the same time. One of the packets could be stalled in place, shunted into buffers or detoured to an alternate route. A collision is happen when two or many nodes send at the same time. The network interface can detect any resulting collision by listenining the channel (carrier sensing). In this case, each involved node waits a random time before resending. Another approach consists in passing a token between the nodes. A node can send a message only when it gets the token. The interconnection structures range from a simple bus to highly concurrent multistage networks capable of performing all possible permutations of its inputs. Topologies of the interconnection network: Crossbar switch limited by the cost of scaling. The cost increases as the square of the number of ports. Multistage interconnections. The cost increase more slowly with the number of ports. On the other hand it has an increased latency and decreased bandwidth per port if all are used at once. Fat tree represents a tree with increased bandwidth higher in the tree, so bandwidth between each level is constant (in a normal tree the bandwidth is reduced in the higher levels) Fully connected networks, linear arrays and rings, multidimensional meshes and tori, trees, hypercubes Bus interconnection obviously it doesn t scale. 32 is the maximum number of processors that can usefully be connected to a single bus.

231 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 233 Topologii NoC-uri 1. SMM pe bus comun (RIC statică) Caracterizată de faptul că RIC este un simplu bus comun partajat în timp de către µprocesoare. Este cea mai simplă arhitectură, dar conflictele potenţiale ale procesoarelor (masterilor) pe busul comun, pot fi multiple. Desigur, există un singur master activ pe bus la un moment dat. Busul comun şi memoria globală (slave) sunt partajate în timp de către masteri. Resursele locale ale masterilor - memorii cache si memorii locale dar si porturi de I/O - au rolul de a diminua traficul pe busul comun. Accesul pe bus se face prin intermediul unui arbitru de priorităţi, centralizat sau distribuit. Arhitectura implică dificultăţi tehnologice legate de numărul maxim de masteri cuplabili (în practică până la 32), reflexii şi diafonii ale semnalelor pe bus. Cum capacităţile şi inductanţele parazite cresc proporţional cu lungimea busului, rezultă că acesta trebuie să fie relativ scurt. Există arhitecturi standardizate de SMM pe bus comun (VME dezvoltat de Motorola pe µp MC680X0, MULTIBUS Intel pentru procesoare I - 80X86). 2. SMM în inel (token ring) reţea statică

232 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 234 Reţea Token-Ring Arhitectura este standardizată conform standardelor IEEE Este utilizată cu precădere în sistemele slab cuplate (reţele locale). Protocolul de comunicaţie are la bază trimiterea unei informaţii binare speciale, numită jeton (token), de la un procesor la celălalt, în mod secvenţial. Un procesor P i, nu poate să trimită un mesaj decât dacă a recepţionat jetonul. Dacă un procesor doreşte să trimită un mesaj la un alt procesor, va aştepta recepţionarea jetonului, apoi va modifica un bit din jeton iar apoi va transmite mesajul cu jetonul modificat pe post de antet. Din acest moment, nu mai circulă jeton prin structură şi deci toate emisiile de mesaje sunt inhibate. După ce procesorul destinaţie a recepţionat mesajul (date sau comenzi), îl va trimite mai departe, spre procesorul sursă. Conform standardului, procesorul sursă va insera din nou jetonul în structură în momentul în care şi-a terminat de transmis mesajul şi a recepţionat începutul propriului mesaj emis. Eficienţa scade proporţional cu numărul procesoarelor din reţea. 3. SMM cu interconectare crossbar (reţea dinamică) Această arhitectură deţine complexitatea cea mai ridicată dintre arhitecturile de SMM, în schimb conflictele procesoarelor la resursele de memorie comună partajată sunt minime. Comunicaţia între orice pereche procesor memorie este întârziată în nodul de conexiune aferent. De remarcat că pot avea loc simultan până la N accese ale procesoarelor la memorie, în ipoteza în care nu există două procesoare care să acceseze acelaşi modul de memorie. Practic se implementează N! funcţii bijective de comunicaţie definite pe mulţimea celor N procesoare, cu valori în mulţimea celor N module de memorie. Pentru evitarea conflictelor de acest gen, se încearcă atunci când este posibil împrăştieri favorabile ale informaţiei în modulele de memorie globală. De exemplu în aplicaţiile pe vectori, dacă

233 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 235 aceştia au pasul 1 atunci scalarii succesivi sunt situaţi în blocuri succesive de memorie, rezultând minimizări ale conflictelor. Reţea crossbar Deşi cea mai performantă, arhitectura devine practic greu realizabilă pentru un număr N ridicat de procesoare, din cauza costurilor ridicate (N 2 noduri). 4. SMM cu reţele de interconectare dinamice multinivele Reprezintă un compromis între SMM unibus şi cele de tip crossbar. Elementul principal al RIC îl constituie comutatorul (complex switch). În general sunt folosite comutatoare cu două intrări şi două ieşiri. Aceste comutatoare pot lucra direct sau în cruce, adică (A C, B D) respectiv (A D, B C). Figura 8.5. Comutator de reţea

234 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 236 Se prezintă mai jos un SMM având o reţea de interconectare pe trei niveluri, într-o topologie BASELINE, cu opt procesoare (P 0, P 7 ) şi opt module de memorie (M 0, M 7 ). Figura 8.6. Interconectare Baseline Cu precizarea că C kj = 0 semnifică faptul că switch-ul C kj lucrează în linie, iar C kj = 1 faptul că lucrează în cruce, k={1,2,3} (coloane) iar j={1,2,3,4}(rânduri), în continuare se prezintă grafurile de comunicare totală procesoare memorii pentru reţeaua BASELINE.

235 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 237 Figura 8.7. Grafuri comunicaţie Baseline

236 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore N Exemplu: F(100) reprezintă graful asociat reţelei de interconectare procesoare memorii, considerând că switchurile C 0 lucrează în cruce iar C 1, C 2 lucrează în linie. Spre deosebire de arhitectura crossbar, în cazul acestor RIC uri, nu este posibilă implementarea oricărei funcţii bijective de comunicaţie f:{p 0, P 1,..., P 7 } {M 0, M 1,..., M 7 }, din cele 8! funcţii bijective posibile, ci doar a celor 8 funcţii de mai sus. De remarcat însă că în acest caz, complexitatea comutatoarelor este mai mare decât în cazul crossbar, în schimb sunt mai puţine. Mai precis, RIC crossbar are N 2 comutatoare elementare în timp ce o astfel de reţea are N 2 doar 4 log N = 2Nlog N <. În schimb, o conexiune procesor- 2 memorie este întârziată aici pe 3 nivele de comutatoare elementare şi nu pe unul singur ca în cazul crossbar. Un dezavantaj important al acestor arhitecturi, zise şi arii de procesoare îl constituie posibilitatea unei căi de comunicare procesor memorie de a bloca alte căi necesare. De exemplu în cazul BASELINE, calea P 0 M 7 blochează interconectarea simultană a oricărora dintre următoarele conexiuni: P 1 M 4, P 1 M 5, P 1 M 6, P 1 M 7, P 2 M 6, P 3 M 6 etc. Rezultă deci că o asemenea RIC este mai puţin potrivită pentru transferuri prin comutare de circuite. În cazul unei reţele cu comutare de pachete, blocarea constă în aşteptarea pachetului într-un buffer asociat comutatorului, până când se va ivi posibilitatea trimiterii sale spre următorul nivel de comutatoare. Desigur, există şi alte topologii de reţele multinivel (BANYAN, DELTA etc.). 5. SMM interconectate în hipercub (statică) Figura 8.8. Interconectare (hiper)cub

237 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 239 În hipercubul k dimensional (binary k-cube) există N = 2 k noduri (procesoare), fiecare de gradul k, adică având legături directe cu k procesoare. Dacă tratăm fiecare etichetă a nodurilor ca o valoare binară semnific/nd adresa acestui nod, nodurile conectate direct diferă printr-o singură coordonată (adiacent codificate). Altfel spus, cei k vecini ai unui procesor P j au etichete binare adiacente cu cea a lui P j. Pentru dimensiuni mai mari decât 3 ale lui k, diagrama de interconectare devine mai laborioasă dar ideea rămâne aceeaşi. Considering a source node having its binary address S and a destination node having its binary address D it is defined the relative address as: R(S, D)=S XOR D. This relative address R(S, D) represents the dimensions that must be crossed to travel from node S to node D and it defines the routing algorithm. The length of the route is equal with the number of logical ones in R(S, D). As an example, considering a simple cube (k=3), source node S=2=010 2 and destination node D=7= In this case R(S, D)=010 XOR 111 = 101. The two logical ones in the obtained result (101) show which bits need to be changed in order to route the message from S to D. This means that there are two routing possibilities: S=010011D=111 or S=010110D=111. Câteva companii incluzând INTEL, NCUBE, FPS etc. au studiat şi au implementat maşini în această reţea. 6. Fat tree Fat tree is a tree with increased bandwidth higher in the tree; so bandwidth between each level is constant rather than reduced in the top levels, as in a normal tree. For example in a N-ary normal tree BW(L k )=N*BW(L k+1 ), where BW(L k ) is the bandwidth in the level k. In a N-ary fat tree BW(L k )=BW(L k+1 ). A (fat) tree has a logarithmic depth. In a fat tree, adding a new level at the top of the tree doubles the number of nodes. Between any two nodes (processors) there are multiple communication paths. This is an advantage in order to avoid congestions and also to implement some fault tolerance facilities. The well known CM-5 supercomputer (Thinking Machine Co, 1991) interconnected up to 1024 processors through a fat tree interconnect. The diameter of a NoC is the length of the maximum shortest path between any two nodes. The routing distance between a pair of nodes is the number of links traversed en route; obviously, it is not necessary the shortest path. Symmetric shared-memory MultiProcessor (SMP) is a shared global memory multiprocessor where the cost of accessing a memory location is the same for all processors. Therefore it has uniform access cost (Uniform Memory Access - UMA). In other words, SMP is a multiprocessor computer architecture where two or more identical processors are connected to a single shared main memory. Most common multiprocessor systems today use SMP architecture.

238 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 240 The question is: what is required to scale the design to a large number of processors? An alternative approach to SMPs is to interconnect complete processors, each with a local memory. This is a non-uniform memory access - NUMA approach or a distributed shared-memory architercture (see next Figure); the local memory controller determines, on the basis of the address, whether to perform a local memory access or a message transaction with a remote memory controller. In the second case a message is sent to the controller in the remote memory to access the data. Also, NUMA is easier to scale. The Figure itself might have two distinct semantics: a shared memory system - if all the memory modules belong to the same global logical address space - or even a message passing system, if each memory module is a local memory attached to the corresponding processor (distributed system, network, where it is not a logically shared memory.) Figura: Processor, Memory, biported, Interconnection Network (IN) Accesses to private data, such code and stack, can be often performed locally. The bandwidth demand placed on the network is reduced. The NUMA approach has become more prevalent at a large scale because of its inherent performance advantages. The cache coherence problem When a write to a shared data occurs there are necessary to assure the coherence to ensure that later reads by other processors get the new data rather than the old data that was replicated into their caches. Replication avoids unnecessary communications. Cache coherence in multiprocessors basically means that a read shall return the value of the latest write as defined by the partial order (dependence order) of memory operation in a valid execution. Cache coherence is maintained if a read always returns the latest write and the latest write is globally performed (meaning that no processor can access the old data value). Memory (cache) coherence might be violated in a multiprocessor with private caches. The problem is caused by shared read-write data structures.

239 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 241 In order to enforce cache coherence in a multiprocessor system it is necessary to make updates to a location appear atomic. A Solution: Write-invalidate All other cache copies are invalidated on a write. Most snoopy cache policies are write invalidate. Main idea: invalidate all copies (if any) before updating local copy. Invalidations and cache misses are broadcast on the bus. Caches and memory snoop the bus and take appropriate action. Se va considera un exemplu care arată cum 2 procesoare pot "vedea" 2 valori diferite pentru aceeaşi locaţie (X) de memorie globală, adică un caz tipic de incoerenţă a unei valori globale shared. Pas Eveniment Conţinut cache Conţinut cache Conţinut Memorie CPU1 CPU2 globală (X) CPU1 citeşte X CPU2 citeşte X CPU1 scrie 0 în X (WT) WB S-a presupus că iniţial, nici una din cele 2 cache-uri nu conţine variabila globală X şi că aceasta are valoare 1 în memoria globală. De asemenea s-au presupus cache-uri de tip WriteThrough - WT (un cache WriteBack - WB ar introduce o incoerenţă asemănătoare). În pasul 3 CPU 2 are o valoare incoerentă a variabilei X. Definiţie: Un SMM este coerent dacă sunt îndeplinite următoarele 3 condiţii: 1. Un procesor P scrie variabila X. Dacă după un timp, P va citi variabila X şi dacă între cele 2 accese la memorie ale lui P nici un alt procesor nu a scris în X, atunci P va citi aceeaşi valoare a lui X cu cea scrisă. 2. Un procesor Pi scrie variabila X. Dacă după un timp, un alt procesor Pj va citi variabila X şi dacă între timp nici un alt procesor nu a scris în X, atunci Pj va citi aceeaşi valoare ca cea scrisă de către Pi. Condiţia nu e triviala, având în vedere exemplul de mai sus (CPU1 scrie "0", CPU2 citeşte "1"). 3. Scrierile la aceeaşi locaţie (X) trebuie serializate prin arbitrare. De exemplu dacă P1 scrie 1 la adresa X şi apoi P2 scrie 2 la aceeasi

240 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 242 adresa, niciodată un procesor nu va putea citi întâi X=2 şi apoi X=1. O nerespectare a unuia din cele 3 principii enuntate mai sus, poate conduce la incoerenţa sistemului de memorie. Fiecare dintre cache-urile care conţine copia unui bloc din memoria globală, conţine de asemenea "starea" acelui bloc d.p.d.v. al procesului de partajare (partajat - "read-only", exclusiv - "read/write", invalid). Aşadar, nu există o centralizare a informaţiei de stare a blocului. Fiecare controller de cache, monitorizează permanent busul comun pentru a determina dacă cache-ul respectiv conţine sau nu conţine o copie a blocului cerut pe busul comun (snooping protocol). În cadrul acestui protocol de monitorizare, există 2 posibilităţi de menţinere a coerenţei funcţie de ceea ce se întâmplă la o scriere: 1) Write Invalidate (WI). Procesorul care scrie determină ca toate copiile din celelalte memorii cache să fie invalidate (se pune bitul de validare V=0 în cadrul blocului respectiv din cache orice acces la acel bloc va fi cu MISS), înainte însă ca el să-şi modifice blocul în cache-ul propriu. Respectivul procesor va activa pe busul comun un semnal de invalidare bloc şi toate celelalte procesoare vor verifica prin monitorizare dacă deţin o copie a blocului; dacă DA, trebuie să invalideze blocul care conţine acel cuvânt. Evident că un anumit bloc invalidat în cache, nu va mai fi scris în memoria globală la evacuare. Astfel, WI permite mai multe citiri simultane a blocului dar o singură scriere în bloc la un anumit moment dat. Este foarte des implementat în SMM. 2) Write Broadcast (Write Update - WBC). Procesorul care scrie pune data de scris pe busul comun spre a fi actualizate toate copiile din celelalte cache-uri. Pentru asta, este util să se ştie dacă un cuvânt este sau nu este partajat (conţinut în alte cache-uri decât cel al procesorului care scrie). Dacă nu e partajat într-un anumit cache, evident că actualizarea (updating) sa în acel cache este inutilă. Este mai puţin utilizat în SMM. Obs. Ambele strategii de menţinere a coerenţei (WI, WBC) pot fi asociate cu oricare dintre protocoalele de scriere în SMM (Write Through respectiv Write Back).

241 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 243 Pas Activitate procesor Activitate pe bus comun Loc.X cache CPU1 Loc.X cache CPU2 Loc. X Memorie globală CPU1 citeşte X Cache Miss (X) CPU2 citeşte X Cache Miss (X) CPU1 scrie 1 în X Invalidare X 1 INV. 0 4 CPU2 citeşte X Cache Miss (X) Coerenţa prin protocol WI În pasul 4, CPU1 abortează ciclul de citire al lui CPU2 din memoria globală şi pune pe busul comun valoarea lui X ("1", copie exclusivă). Apoi, scrie (actualizează) valoarea lui X în cache-ul lui CPU2 şi în memoria globală iar X devine o variabilă partajată. Mai jos, se prezintă un exemplu de protocol de coerenţă WBC, bazat pe un protocol de scriere în cache de tip "Write Through": Pas Activitate procesor Activitate pe bus comun Loc.X cache CPU1 Loc.X cache CPU2 Loc. X Memorie globală CPU1 citeşte X Cache Miss (X) CPU2 citeşte X Cache Miss (X) CPU1 scrie 1 în X Write update X CPU2 citeşte X (HIT) Coerenţa prin protocol WBC Diferenţele de performanţă între protocoalele de coerenţă WI şi WBC, provin în principal din următoarele caracteristici: a) Dacă acelaşi CPU scrie de mai multe ori la aceeaşi adresă fără apariţia intercalată a unor citiri din partea altor procesoare sunt necesare scrieri multiple pe busul comun în cazul WBC, în schimb e necesară doar o invalidare iniţială în cazul WI. b) WBC lucrează pe cuvinte (deci la scrieri repetate în acelaşi bloc accesează repetat busul comun), în timp ce WI lucrează pe bloc (la

242 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 244 scrieri repetate într-un bloc, determină doar o invalidare iniţială a acelui bloc din celelalte cache-uri care îl conţin). c) Întârzierea între scrierea unui cuvânt de către un procesor şi citirea respectivei valori de către un alt procesor, este în general mai mică într-un protocol WBC (hit) decât într-unul WI (miss). d) Strategia WI, prin invalidarea blocurilor din celelalte cache-uri, măreşte rata de miss. În schimb, strategia WBC măreşte traficul pe busul comun. Actualmente, strategia WI este preferată în majoritatea implementărilor. În continuare, se va considera un protocol de coerenţă WI şi unul de scriere de tip WB. Pentru implementarea protocolului WI, procesorul accesează busul comun şi distribuie pe acest bus, adresa de acces spre a fi invalidată în toate copiile partajate. Toate procesoarele, monitorizează continuu busul, în acest scop. Dacă adresa respectivă este caşată, atunci data aferentă este invalidată. În plus faţă de procesele de invalidare, este de asemenea necesar în cazul unui miss în cache, să se localizeze data necesară. În cazul WT este simplu pentru ca cea mai recentă copie a blocului respectiv se află în memoria globală. Pentru un cache "Write Back" însă, problema este mai complicată întrucât cea mai recentă valoare a datei respective se află într-un cache mai degrabă decât în memoria globală. Soluţia constă în următoarea: dacă un anumit procesor deţine o copie a blocului accesat, având biţii D=1 (dirty) şi V=1 (valid), atunci el furnizează pe busul comun data respectivă şi abortează accesul la memoria globală (vezi pasul 4, tabel sus, pagina anterioară). În cazul unei scrieri cu MISS (WI, WB), invalidarea blocului în care se scrie, nu are sens să se facă dacă nici un alt cache nu îl conţine. Rezultă că e necesar să se ştie starea unui anumit bloc (partajat/nepartajat) în orice moment. Aşadar în plus faţă de biţii de stare D şi V, fiecare bloc mai poate deţine un bit P (partajat sau nu). O scriere într-un bloc partajat (P=1), determină invalidarea pe bus şi marchează blocul ca "privat" (P=0), adică respectivul cache deţine copia exclusivă a acelui bloc. Procesorul respectiv se numeşte în acest caz, proprietar (owner). Dacă ulterior, un alt procesor citeşte blocul respectiv, acesta devine din nou partajat (P=1). Un protocol de coerenţă (WI,WB) se implementează printr-un controller de tip automat finit, dedicat, plasat în fiecare nod. Controllerul răspunde atât la cererile CPU-ului propriu cât şi la cererile de pe busul comun. Ca urmare a acestor cereri, controllerul modifică "starea" blocului din cache-ul local şi utilizează busul pentru accesarea sau invalidarea informaţiei. În principiu, un bloc din cache poate fi într-una din următoarele

243 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore stări: invalid, partajat (read only) şi exclusiv (read - write). Pentru simplitate, protocolul implementat nu va distinge între un "write hit" şi un "write miss" la un bloc "partajat" din cache; ambele se vor trata ca "write miss"-uri. Când pe busul comun are loc un "write miss", fiecare CPU care conţine în cache o copie a blocului accesat pe bus, o va invalida. Dacă blocul respectiv este "exclusiv" (doar în acel cache), se va actualiza ("write back"). Orice tranziţie în starea "exclusiv" (la o scriere în bloc), necesită apariţia unui "write miss" pe busul comun, cauzând invalidarea tuturor copiilor blocului respectiv, aflate în alte cache-uri. Apariţia unui "read miss" pe bus, la un bloc exclusiv, va determina punerea lui ca "partajat" de către procesorul proprietar. Problems: If two processes update a variable alternately, data will continually migrate between two caches with a high miss rate (this is known as the ping-pong effect.) If one process updates a data structure which many processes use, write-invalidate will also perform badly. A Snooping Protocol (Write Invalidate, Write Back) Exclusive (Modified), Shared, Invalid ESI, known as MSI protocol, too. Every cache line is marked with one of the four following states (coded in two additional bits): E Exclusive (Modified): The cache line is present only in the current cache. S - Shared: Indicates that this cache line may be stored also in other caches of the machine. I - Invalid: Indicates that this cache line is invalid (after a write). Source Request type State of the addressed cache block CPU Read hit * Shared (read only) or Exclusive (Owner, read/write) Function, explanations, comments Read data from the cache. Obviously, the block will transit in the same state. Read miss Invalid Place Read_miss signal on the bus. The block will transit in Shared state (even if it will be loaded from the main memory and not from a cache). (Activating Read_miss signal on the bus will transit all the valid block copies in the Shared state.) Read miss Shared (the data is in other caches) Interference (conflict) miss; place Read_miss signal on the bus. The block

244 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 246 Read miss Exclusive (data in an other cache) (having new data) will transit in the same Shared state (trivial transition) Care cache ii da data? Arbitrare Fiind in Shared state nu e necesara evacuarea prealabila asta se va face numai in starea Exclusive (v. urmatoarea) Conflict miss; write back the block in the main memory if its Dirty_bit=1 (otherwise, it will be lost; see further the MESI protocol). After this, place Read_miss signal on the bus. The block will transit in the Shared state. Write hit * Exclusive Write data in cache s block. The block will transit in Exclusive state (no effective transition). Write hit * Shared Place Write_miss (yes!) signal on the bus (this signal will invalidate all the valid copies stored in other caches) The block will transit in Exclusive state. Write miss Invalid Place Write_miss signal on the bus. The block will transit in Exclusive state (after it will be allocated from the next level cache or from the main memory). Write miss Shared Conflict miss; (Eviction); place Write_miss signal on the bus. The block will transit in Exclusive state (after it will be allocated from the next level cache or from the main memory). Write miss Exclusive Conflict miss; Write back in the main memory the addressed bock (this operation might be avoid in MESI protocol; see further). Then place Write_miss signal on the bus. The block will transit (trivial) in the same Exclusive state. BUS ** Read_miss Shared No action (if it attempts to share data, it will produce conflicts on the common bus with other sources arbitration); allow to the cache having an Exclusive copy to service read miss (thus a unique provider); otherwise permit to main memory to offer the data The next sate will be the same (Shared) See MOESI! Read_miss Exclusive Attempt to share data (unique source); place

245 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 247 the addressed cache block (momentary in Exclusive state) on the bus and change its state to Shared Write_miss Shared Attempt to write a shared block; invalidate the block (V=0) Write_miss Exclusive Attempt to write block that is exclusive elsewhere; write back the cache block in the main memory and make it Invalid in the (owner) cache. * During a hit access, obviously, the block can t be invalid (V bit=0) ** Read_miss or Write_miss to an Invalid block No action All these actions are resumed in the following finite state machine representations. Figura preluata din cartea Hennessy si Patterson [Hen07] (v. bibliografia)

246 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 248 MESI protocol involves also that every cache line is marked with one of the four following states (coded in two additional bits): M - Modified: The cache line is present only in the current cache, and it is dirty; thus it has been modified from the value in main memory. The cache is required to write the data back to main memory at some time in the future (evicting process), before permitting any other read of the (no longer valid) main memory state. E - Exclusive: The cache line is present only in the current cache, but is clean, thus it matches main memory. This means that when the block will be evicted it will be not necessary to write it back to the main memory. This represents an advantage comparing with the previous presented ESI MSI protocol. S - Shared: Indicates that this cache line may be stored in other caches of the machine. I - Invalid: Indicates that this cache line is invalid. Therefore, a MESI protocol might be equivalent with an MSI protocol if the blocks belonging to the caches have an associated Dirty bit. MOESI protocol involves also that every cache line is marked with one of the five following states (coded in three additional bits): M - Modified: The cache line is present only in the current cache, and it is dirty; it has been modified from the value in main memory. The cache is required to write the data back to main memory at some time in the future (evicting process), before permitting any other read of the (no longer valid) main memory state. O - Owned: A cache line in the owned state holds the most recent correct copy of the data. The owned state is similar to the shared state in that other processors can hold a copy of the most recent, correct data. However, unlike the shared state the copy in main memory can be incorrect. Only one processor can hold the data in the owned state all other processors must hold the data in the shared state. Owned =Modified AND Non-Shared. States M and O are both Dirty but M is exclusively Dirty. The automata will transit in O state from M state in a Read_miss case on the bus. (Se ajunge in O din M cand un alt procesor vrea sa citeasca valoarea. Procesorul care i-o da trece MO iar cel care o citeste trece in S. Avantajul starii O: se stie clar care procesor furnizeaza valoarea, fara arbitrare; altfel, nu s-ar sti, celelalte copii, din celelalte cache-uri, fiind Shared.) Question: Why the automata transits in S state from E state when a Read_miss occurs on the bus instead of transiting in O state? Debate! E - Exclusive: The cache line is present only in the current cache, but is clean, thus it matches main memory. This means that when the block will be evicted it will be not necessary to write it back to main memory. S - Shared: Indicates that this cache line may be stored in other caches of the machine. The copy in main memory is also the most recent, correct copy of the data (if no other processor holds it in owned state). I - Invalid: Indicates that this cache line is invalid.

247 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 249 Livelocks should occur in a snooping protocol if it is not carefully designed. Suppose multiple processors quite simultaneously write to the same shared memory location and, initially, no processor has cached a copy of that data. In a defavourable case the following scenario would be possible: a certain processor (P1) that attempts to write the corresponding block, firstly brought the block in its cache, put it in the Modified state and invalidates all the potential copies belonging to other processors. Now, P1 should try to effectively write the fetched block but, before it completes its writing process, the block is invalidated by another processor (P2) that attempts to write, too. Now P1 s write generates a miss and the cycle is repeating indefinitely. To avoid such a livelock, after a processor (P1) obtaines exclusive ownership its write process must be atomic and therefore it must be allowed to complete the write process before loosing the exclusive ownership. A Directory based Protocol (Write Invalidate, Write Back) A snooping protocol requires communication with all caches on every cache miss, including writes of potentially shared data. The absence of a centralized structure to track the state of the caches is advantageous because it allows it to be inexpensive. On the other hand it is not scalable. Therefore it is necessary to develop scalable shared memory cache coherence protocols, like the so called directory based protocols. A directory tracks the state of each block that may be cached (which caches have copies of the block, if the block is dirty or not, etc.). Thus, each memory block has an associate entry in the directory structure. It seems that the number of entries is proportional to the product of the number of processors and the number of memory blocks. For more than 200 processors the directory overhead starts to be intolerable. Thus, for larger multiprocessors, there are needed methods to allow the directory structure to be efficiently scaled. The methods that have been used either try to keep information for fewer blocks (e.g., only those in caches rather than all memory blocks) or try to keep fewer bits per entry by using individual bits to stand for a small collection of processors. To prevent the directory from becoming the bottleneck, the directory is distributed along with the memory, so that different directory accesses can go to different directories, just as different memory requests go to different memory modules. A distributed directory retains the characteristic that the sharing status of a block is always in a single known location. This property is what allows the coherence protocol to avoid broadcast. Next Figure shows how the distributed-memory multiprocessor looks with the directories added to each node. Obviously, a shared block has always an unique directory entry. A directory protocol also can be used to reduce the bandwidth demands in a centralized shared-memory machine [Hen07].

248 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 250 Fig. preluata din cartea Hennessy si Patterson [Hen07] (v. bibliografia) A directory is added to each node to implement cache coherence in a distributedmemory multiprocessor. Each directory is responsible for tracking the caches that share the memory addresses of the portion of memory in the node. The directory may communicate with the processor and memory over a common bus, as shown, or it may have a separate port to memory, or it may be part of a central node controller through which all intranode and intemode communications pass. Citat din [Hen07] Just as with a snooping protocol, there are two primary operations that a directory protocol must implement: handling a read miss and handling a write to a shared, clean cache block. (Handling a write miss to a block that is currently shared is a simple combination of these two.) To implement these operations, a directory must track the state of each cache block. In a simple protocol, these states could be the following: Shared One or more processors have the block cached, and the value in memory is up to date (as well as in all the caches). Uncached No processor has a copy of the cache block. Modified Exactly one processor has a copy of the cache block, and it has written the block, so the memory copy is out of date. The processor is called the owner of the block. In addition to tracking the state of each potentially shared memory block, we must track which processors have copies of that block, since those copies will need to be invalidated on a write. The simplest way to do this is to keep a bit vector for each memory block. When the block is shared, each bit of the vector indicates whether the corresponding processor has

249 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 251 a copy of that block. We can also use the bit vector to keep track of the owner of the block when the block is in the exclusive state. For efficiency reasons, we also track the state of each cache block at the individual caches. The states and transitions for the state machine at each cache are identical to what we used for the snooping cache, although the actions on a transition are slightly different. The process of invalidating or locating an exclusive copy of a data item are different, since they both involve communication between the requesting node and the directory and between the directory and one or more remote nodes. In a snooping protocol, these two steps are combined through the use of a broadcast to all nodes. Citat din [Hen07] Write-update (Write broadcast) All other cache copies are updated on a write. Main memory may or may not be updated. Snoopy cache policies could be modified to write-update. Problems: May result in many pointless updates to data structures left behind in caches by processes that have migrated to other processors. Particularly a problem with large caches where data may linger for some time before being flushed. A multi-core CPU (or chip-level multiprocessor, CMP) combines two or more independent cores into a single package comprised of a single piece silicon integrated circuit, called die, or more dies packaged together. A multi-core microprocessor implements multiprocessing in a single physical package. Cores in a multicore device may share a single coherent cache at the highest on-device cache level (e.g. L2 for the Intel Core 2) or may have separate caches (e.g. current AMD dual-core processors). Latentele miss-urilor cache to cache mai mici decat la clasicele SMP, largimea de banda a bus-urilor de interconectare mai mare etc. The processors also share the same interconnect to the rest of the system. A system with N cores is effective when it is presented with N or more threads concurrently. We need a parallel programming language showing how a parallel algorithm might be executed by a given parallel processor. Some HLL language extensions (pragmas - OpenMP) useful for describing a multiprocessor algorithm are [Jor03]: - fork <label>; start a new process executing at <label>. The original process continues with the statement following the fork. - join <integer>; join <integer> processes into one. The original process will proceed only after the specified number of processes have all executed join. - shared <variable list>; make the storage class of the variables shared. The declared variables are shared by all processes. - private <variable list>; make the storage class of the variables private. Each process has its own private copy of the variable referred to by that name.

250 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 252 A Parallel Program Example [Jor03]: N c 1 = k= 0 /* C :=AxB, ij ik kj */ a b

251 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 253 private i, j, k; shared A[N,N], B[N,N], C[N,N], N; /* Start N-1 new processes, each one for a different C column. */ for j := 0 step 1 until N-2 fork MULCOL; /* The original main process reaches this point and works for the last C column. */ j := N-1; MULCOL: /* Executed by all N processes, for j = 0 to N-1, each one working asynchronously to a different C column. SPMD concept */ for i := 0 step 1 until N-1 begin C[i,j] := 0; for k := 0 step 1 until N-1 C[i,j] := C[i,j] + A[i,k] * B[k,j]; end join N; /* Join all the N processes into one. */ Another Parallel Program Example (adapted from [Jor03]) The n-1 st order linear recurrence system of n equations (general linear recurrence) has the following solutions: x 1 = c 1 x 2 = c 2 + a 21 x 1 x 3 = c 3 + a 31 x 1 + a 32 x 2 x 4 = c 4 + a 41 x 1 + a 42 x 2 + a 43 x 3, and so on The current row x k+1 is RAW dependent by the previous one x k. A preliminary parallel pseudo-code could be the following: shared n, a[n,n], x[n], c[n]; private i, j; for i=1 step 1 until n-1 fork DOROW; /* a process to do each row x[i]*/ i=n; /*the initial process works for i=n.*/ DOROW: x[i] = c[i];//parallelism n threads for j=1 step 1 until i-1 x[i] = x[i] + a[i,j]*x[j];//paralelism n threads join n; Some Problems: Processes must receive a private copy of i, with distinct values for each process, at the time they are forked. It is not clear how it should do this. All processes must proceed together through the loop on j. The final value of an element x[k] must be available before it is accessed by processes having values of i>k (RAW conditions). Therefore, it is necessary a data- synchronization (see below). Otherwise, the program should be incorrectly processed. There is nothing in the program to guarantee this.

252 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 254 join n, tells how many processes to wait for, without identifying them. These problems must be clarified in a refined program s version. The mechanisms of parameter passing for function call in sequential languages can also be used for process instantiation in parallel languages. The variable i should be passed by value to the new created process. Create/Call create starts a new instruction stream executing the procedure in parallel with the process doing the create while the latter process continues without waiting for a return. A return in a procedure that can be invoked by either a call or create is interpreted as quit (create; otherwise the n-1 procedures will inadequately return in the main program) or sequential return (call). This form of process termination makes it necessary to use an explicit counter to determine when all processes have completed. shared n, a[n,n], x[n], c[n], done; private i; done = n; /* no. of processes*/ for i=1 step 1 until n-1 create dorow (i, done, n, a, x, c); /*create (n-1) threads.*/ i=n; call dorow (i, done, n, a, x, c); /*call the n-th thread.*/ while (done 0); /*loop until all n thread instances finished.*/ procedure dorow (value i, done, n, a, x, c) shared n, a[n,n], x[n], c[n], done; private i, j; x[i] = c[i]; for j=1 step 1 until i-1 x[i] = x[i] + a[i,j]*x[j]; done = done -1; return; /* quit-create or return-call*/ end procedure Synchronization Data-based synchronization (Producer/Consumer Synchronization) associates a one bit full/empty state with each shared variable). It uses synchronized read and write operations to access the value of the shared variable only when it has a specified state. Assumed syntaxes for producer/consumer variables: produce <shared var> = <expression>; it waits for the variable to be empty (consumed), writes its value, and sets it full (new value!). consume <shared var> into <private var>; it waits for the variable to be full (produced), reads its value, and sets it empty (it could be now produced by another write). copy <shared var> into <private var>; it waits for full and reads, but does not set empty. void <shared var>; it initializes the shared variable s state to empty. shared n, a[n,n], x[n], c[n], done; private i;

253 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 255 done = n; /* no. of processes*/ for i=1 step 1 until n-1 {void x[i]; create dorow (i, done, n, a, x, c); } /*create n-1 procedures.*/ i=n; void x[i]; call dorow (i, done, n, a, x, c); /*call the n-th process.*/ while (done 0); /*loop until all n procedure instances finished.*/ procedure dorow (value i, done, n, a, x, c) shared n, a[n,n], x[n], c[n], done; private i, j, sum, priv; sum = c[i]; for j=1 step 1 until i-1 {copy x[j] into priv; /*get x[j] when it is available.*/ sum = sum + a[i,j]*priv; } produce x[i] = sum; /*make x[i] available to others.*/ done = done -1; return; end procedure Atomicity If the statement done = done -1; may be executed simultaneously by several processes, there could be some problems. Even if in this concrete program it seems to be not possible (the n processes seems to sequentially access the statement), in other parallel programs this fact would be possible. The statement is not a single operation. If two processes access the value of done variable in some order the final value could be wrong (done -1 instead of done-2 due to a Read - Modify Write hazard). A similar problem consists in the fact that even a read/write instruction may take more than one bus operation. As a consequence, a program that can ran correctly on a 64-bit computer when moved to a machine that supports 64-bit operations with 32 bit instructions. shared n, a[n,n], x[n], c[n], done; private i; done = n; /* no. of processes*/ for i=1 step 1 until n-1 {void x[i]; create dorow (i, done, n, a, x, c); } /*create n-1 procedures.*/ i=n; void x[i]; call dorow (i, done, n, a, x, c); /*call the n-th process.*/ while (done 0); /*loop until all n procedure instances finished.*/ procedure dorow (value i, done, n, a, x, c) shared n, a[n,n], x[n], c[n], done; private i, j, sum, priv;

254 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 256 sum = c[i]; for j=1 step 1 until i-1 {copy x[j] into priv; /*get x[j] when it is available.*/ sum = sum + a[i,j]*priv; } produce x[i] = sum; /*make x[i] available to others.*/ critical /*lock/ done = done -1; /*decrement shared variable; control-based synchronization*/ end critical /*unlock*/ return; end procedure Mutual exclusion, critical section. Critical sections of the same name exclude each other but may execute concurrently with critical sections of different names [ Jor03]. Processes can be created at the beginning of the program, execute a common set of code that distributes work in parallel loop and terminate at the end of the program - SPMD process creation and termination. In this style, multiple processes, each distinguished by a unique identifier, execute a single program simultaneously but not necessary synchronously [Jor03]. shared P; private id; for id=0 step 1 until P-2 create parmain (id, P); id = P-1; call parmain (id, P); call exit (); Work on automatic parallelizing compilers to speed up the execution of parallel programs using a multiprocessor architecture is a big difficult challenge. The main problem is not: Uniprocessor components Network topologies Unavailability of appropriate languages The essential difficulties in writing effective parallel programs are: Parallel programs are inherently harder to develop Need to understand the underlying hardware Programs tend not to be portable Amdahl s law; a very small part of a program that is inherently sequential can severely limit the attainable speedup. Consistenta variabilelor partajate

255 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 257 Un program paralel trebuie să specifice ordinea operațiilor de scriere-citire. Consistența secvențială (CS): In_Proc[data-flow] AND Inter_Pr[Arbitrary N_Expl_Sync] A parallel program consists of one or more threads of control, operating on data. A parallel programming model specifies what data can be named by threads, what operations can be performed on the named data, and what ordering exists among these operations. The most straightforward ordering is the so called sequential program order, meaning that, in programmer s view, variables are read and modified in the order specified by the program. In fact, the compiler and hardware preserve the dependence order. A parallel program must coordinate the activity of its threads to ensure that the dependences within the program are enforced. This requires explicit synchronization operations when the ordering implicit in the basic operations are not sufficient. Coerenţa cache-urilor asigură o viziune consistentă a memoriei pentru diversele procesoare din sistem. Nu se răspunde însă la întrebarea "CÂT de consistentă?", adică în ce moment trebuie să vadă un procesor că o anumită variabilă a fost modificată de un altul? Exemplu: (P1) A=0; A=1; L1: if(b==0)... (P2) B=0; B=1; L2: if(a==0)... În mod normal, este imposibil pentru ambele programe rezidente pe procesoare diferite (P1, P2) să evalueze pe adevărat condiţiile L1 şi L2 întrucât dacă B=0 atunci A=1 şi dacă A=0 atunci B=1. Şi totuşi, acest fapt s- ar putea întâmpla. Să presupunem că variabilele partajate A şi B sunt caşate pe '0' în ambele procesoare. Dacă de exemplu, între scrierea A=1 în P1 şi invalidarea lui A în P2 se scurge un timp suficient de îndelungat, atunci este posibil ca P2 ajuns la eticheta L2 să evalueze (eronat) A=0. Cea mai simplă soluţie constă în forţarea fiecărui procesor care scrie o variabilă partajată, de a-şi întârzia această scriere până în momentul în care toate invalidările (WI) cauzate de către procesul de scriere, se vor fi terminat. Această strategie simplă se numeşte consistenţă secvenţială. Ea impune ca orice simulare a procesării unui anumit program,

256 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 258 prin respectarea secvenţialităţii interne din cadrul unui fir (data-flow order) şi, respectiv, prin ordinea aleatoare de execuţie a firelor între ele, atunci când nu este specificată una anumită, să conducă la aceleaşi rezultate finale. Altfel spus, un program scris corect va duce la aceleaşi rezultate, indiferent de întreţeserea firelor. Deşi consistenţa secvenţială prezintă o paradigmă simplă, totuşi ea reduce performanţa, în special pentru sistemele cu un număr mare de procesoare sau cu reţele de interconectare de latenţe ridicate. Obs. Consistenţa secvenţială, nu permite de exemplu implementarea unui "write buffer" la scriere, care pe baza captării adresei şi datei procesorului, să se ocupe în continuare de procesul de scriere efectivă a datei în memorie, degrevând astfel procesorul de acest proces. ATOMIZĂRI ŞI SINCRONIZĂRI (paragraf facultativ) În cazul proceselor de sincronizare, dacă un anumit procesor "vede" semaforul asociat unei variabile globale pe '1' (LOCK - ocupat), are 2 posibilităţi de principiu: a) Să rămână în bucla de testare a semaforului până când acesta devine '0' (UNLOCK) - strategia "spin lock" b) Să abandoneze intrarea în respectivul proces, care va fi pus într-o stare de aşteptare şi să iniţieze un alt proces disponibil - comutare de task-uri. Strategia a) deşi des utilizată, poate prelungi mult alocarea unui proces de către un anumit procesor. Pentru a dealoca un proces (variabila aferentă), procesorul respectiv trebuie să scrie pe '0' semaforul asociat. Este posibil ca această dealocare să fie întârziată - dulce ironie! - datorită faptului că simultan, alte N procesoare doresc să testeze semaforul în vederea alocării resursei (prin bucle de tip Read - Modify - Write). Pentru evitarea acestei deficienţe este necesar ca o cerere de bus de tip "Write" să se cableze ca fiind mai prioritară decât o cerere de bus în vederea unei operaţii tip "Read - Modify - Write". Altfel spus, dealocarea unei resurse este implementată ca fiind mai prioritară decât testarea semaforului în vederea alocării resursei. Strategia b) prezintă deficienţe legate în special de timpii mari determinaţi de dealocarea/alocarea proceselor (salvări/restaurări de contexte). În ipoteza că în SMM nu există mecanisme de menţinere a coerenţei cache-urilor, cea mai simplă implemetare a verificării disponibilităţii unei variabile globale este următoarea (spin lock):

257 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 259 li R2, #1; R2 1 test: lock exchg R2,0(R1) ; atomică bnez R2,test Dacă însă ar exista mecanisme de coerenţă a cache-urilor, semaforul ar putea fi ataşat local. Primul avantaj ar consta în faptul că testarea semaforului ('0' sau '1') s-ar face din cache-ul local fără să mai fie necesară accesarea busului comun. Al 2-lea avantaj - de natură statistică - se bazează pe faptul dovedit, că e probabil ca într-un viitor apropiat procesorul respectiv să dorească să testeze din nou semaforul (localitate spaţială şi temporală). În vederea obţinerii primului avantaj, bucla anterioară trebuie modificată. Fiecare "exchg" implică o operaţie (ciclu) de tip "Write". Cum secvenţa anterioară de testare a semaforului poate fi executată în paralel de mai multe procesoare, se pot genera concurenţial mai mulţi cicli (cereri) de tip "Write". Cele mai multe, vor conduce la miss-uri, întrucât fiecare procesor încearcă să obţină semaforul într-o stare "exclusivă". Aşadar, bucla se va modifica în acest caz ca mai jos: test: lw R2,0(R1) ; testare pe copia locală bnez R2, test ; a semaforului li R2, #1 ; setare concurenţială a lock exchg R2,0(R1) ; semaforului de către bnez R2,test ; procesoare (un singur câştigător) Să studiem acum implicaţiile acestei secvenţe de program într-un SMM cu 3 procesoare P0, P1, P2 implementând un protocol de coerenţă a cache-urilor de tip WI şi un protocol de scriere în cache de tip "Write Back". Pas Procesor P 0 Procesor P 1 Procesor P 2 Stare semafor Are Sem = 1 Testare Testare 1 (LOCK) pus Sem=0? Sem=0? chiar de el NU! NU! 2 Termină proces şi pune Sem = 0 în cache Recepţionează invalidare în cache Recepţioneaz ă invalidare în cache Activitate pe BUS-ul comun Partajat - Exclusiv Write invalidate pentru Sem de la P 0

258 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore Read miss Read miss Partajat Arbitru serveşte pe P 2 ; Write back de la P WAIT (acces la bus) Sem = 0 Partajat Read miss-ul pentru P 2 satisfăcut 5 - Sem = 0 Execută exchg cache miss satisfăcut 6 - Execută Terminare Exclusiv exchg exchg. cache miss Primeşte 0, scrie Sem = Terminare Intră în Partajat P 1 servit exchg. secţiunea Primeşte 1 critică de LOCK! program 8 - Testează în prima buclă dacă Sem = 0? Conlucrarea a trei procese într-un SMM Partajat Read miss-ul pentru P 1 P 2 servit; Write invalidate Sem Tabelul 8.4. Pentru a minimiza traficul pe busul comun introdus de către instrucţiunea "exchg", secvenţa anterioară se poate rafina ca mai jos: test: ll R2,O(R1) bnez R2,test li R2,#1 sc R2,O(R1) ;un singur P k o va executa cu begz R2,test ; succes, restul, nu scade traficul pe bus Sincronizarea la barieră Este o tehnică de sincronizare deosebit de utilizată în programele cu bucle paralele. O barieră forţează toate procesele să aştepte până când toate au atins bariera, abia apoi permiţându-se continuarea acestor procese. O implementare tipică a unei bariere poate fi realizată prin 2 bucle succesive: una atomică în vederea incrementării unui contor sincron cu fiecare proces care ajunge la barieră iar cealaltă în vederea menţinerii în aşteptare a

259 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 261 proceselor până când aceasta îndeplineşte o anumită condiţie (test); se va folosi funcţia "spin (cond)" pentru a indica acest fapt. Se prezintă implementarea tipică a unei bariere: LOCK(counterlock) Proces if(count==0) release=0 ; /*şterge release la început*/ atomic count=count+1 ; /*contorizeazã procesul ajuns la barieră*/ UNLOCK(counterlogic) if(count==total) { /*toate procesoarele ajunse!*/ count=0; release=1; } else { /*mai sunt procese de ajuns*/ spin(release=1); /*aşteaptă până ce ajunge şi ultimul*/ } total nr. maxim al proceselor ce trebuie să atingă bariera release utilizat pentru menţinerea în aşteptare a proceselor la barieră Există totuşi posibilitatea de exemplu, ca un procesor (proces) să părăsească bariera înaintea celorlalte care ar sta în bucla "spin (release=1)" şi ar rezulta o comutare de task-uri chiar în acest moment. La revenire vor vedea "release=0" pentru că procesul care a ieşit a intrat din nou în barieră. Rezultă deci o blocare nedorită a proceselor în testarea "spin". Soluţia în vederea eliminării acestui hazard constă în utilizarea unei variabile private asociate procesului (local_sense). Bariera devine: local_sense=!local_sense; LOCK(counterlock); count++; UNLOCK(counterlock); if(count==total) { count=0; release=local_sense; } else {

260 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 262 } spin(release=local_sense); Dacă un proces iese din bariera urmând ca mai apoi să intre într-o nouă instanţă a barierei, în timp ce celelalte procese sunt încă în barieră (prima instanţă), acesta nu va bloca celelalte procese întrucât el nu resetează variabila "release" ca în implementarea anterioară a barierei. Obs. D.p.d.v. al programatorului secvenţial, bariera anterioară este corectă. Message passing architectures Employs complete computers as building blocks and provides communication between processors as explicit I/O operations (send/receive). The main message passing architecture scheme is essentially the same as the NUMA shared memory scheme. The primary difference is that communication is integrated at the I/O level, like in networks. Send specifies a local data buffer that is to be transmitted, a receiving process (on a remote processor) and a tag identifying the sender. Receive specifies a sending process, a local data buffer into witch the receive data will be stored and a matching rule (tag). Parallel programs using message passing are usually structured. Frequently, all nodes execute identical copies of the program, with the same code and private variables. Message passing models assume a collection of processes each operating in a private address space and each able to name the other processes. Send/receive operate on the local address space and the global process space. Each send/receive pair is a specific point-to-point synchronization operation. Interconnection network topologies are: ring, grid (2D, 3D), hypercube, fully connected, etc. In early implementations each processor communicates with its neighbors. For example, initially, in a hypercube topology each node communicated through two FIFO buffers (send/receive) with N adjacently codified nodes, for a total of 2 N nodes. The direct FIFO design was soon replaced with DMAs. The use of DMA allowed nonblocking sends (the sender initiates a send and continues with useful computations while the send completes). On the receiving end, the transfer is accepted through a DMA transfer by the message layer into a buffer and queued until the target process performs a matching receive and data is stored into receiver process address space. In present message layers provide support for communication between arbitrary processors rather than only between physical neighbors. So, each node store and forward the message (routing). A fully connected N processor system has maximum concurrency at a very high cost. 2 C N =N(N-1)/2 bidirectional links providing Evolution has blurred the once clear difference between the shared memory and message passing approaches. Related to the communication operations available to the user process,

261 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 263 traditional message passing operations (send/receive) are supported on most shared memory machines through shared buffer storage. Flags or locks are used to control access to the buffer and to indicate events such as message arrival. Where the implicit ordering is not sufficient, explicit synchronization operations are required. Parallel programs require two types of synchronization: Mutual exclusion ensures that a certain action is performed by only one thread or process at a time. This is accomplished by locking the program s sequence upon entry and unlocking it on exit. If several processes arrive simultaneously only one will get in and the others re waiting. The order in which the processes are allowed to enter doesn t matter and it may vary from one execution to the next one. Events are used to inform other processes that some point of execution has been reached, so they can proceed knowing that certain dependences have been satisfied. If one process writes a value that another process is supposed to read, an event synchronization operation must take place to indicate that the value is ready to be read. Events may be point-to-point, involving pair of processes, or they may be global, involving all processes or a group of processes. The idea of PIM (Processing in Memory) is to overcome the bottleneck between the processor and main memory by combining a processor and memory on a single chip. In a PIM architecture: the CPUs are much closer electrically to the memory arrays containing instructions and data. the number of bits available from each access can be literally orders of magnitude greater than can be transferred in a single clock cycle from today's conventional memory chip to today's conventional (and separate) CPU chip or cache system. The benefits of a PIM architecture are: reduced memory latency, increases memory bandwidth, simplifies the memory hierarchy, provides multi-processor scaling capabilities avoids the Von Neumann bottleneck. This means that: much of the expensive memory hierarchy can be dispensed with, CPU cores can be replaced with simpler designs, less power is used by PIM, less silicon space is used by PIM. Currently there is about an order of magnitude reduction in latency.

262 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 264 PIM is easily scaled: multiple PIM chips connected together forming a network of PIM cells, such scaled architectures are called Cellular architectures. Cellular architectures consist of a high number of cells (PIM units): with tens of thousands up to one million processors, each cell (PIM) is small enough to achieve extremely largescale parallel operations, to minimise communication time between cells, each cell is only connected to its neighbours. Cellular architectures are threaded: each thread unit is independent of all other thread units, each thread unit serves as a single in-order issue processor, each thread unit shares computationally expensive hardware such as floating-point units, there can be a large number of thread units (1,000s if not 100,000s of thousands) therefore they are massively parallel architectures. Recommendations [Asa06]: The overarching goal should be to make it easy to write programs that execute efficiently on highly parallel computing systems The target should be 1000s of cores per chip, as these chips are built from processing elements that are the most efficient in MIPS (Million Instructions per Second) per watt, MIPS per area of silicon, and MIPS per development dollar. Instead of traditional benchmarks, use 13 Dwarfs to design and evaluate parallel programming models and architectures. (A dwarf is an algorithmic method that captures a pattern of computation and communication.) Autotuners should play a larger role than conventional compilers in translating parallel programs. Automatic Design Space Exploration To maximize programmer productivity, future programming models must be more human-centric than the conventional focus on hardware or applications. To be successful, programming models should be independent of the number of processors. To maximize application efficiency, programming models should support a wide range of data types and successful models of parallelism: task-level parallelism, word-level parallelism, and bit-level parallelism. Architects should not include features that significantly affect performance or energy if programmers cannot accurately measure their impact via performance counters and energy counters. Traditional operating systems will be deconstructed and operating system functionality will be orchestrated using libraries and virtual machines. To explore the design space rapidly, use system emulators based on Field Programmable Gate Arrays (FPGAs) that are highly scalable and low cost.

263 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 265 References 1. [Asa06] Asanovic K. et al., The Landscape of Parallel Computing Research: A View from Berkeley, Technical Report No. UCB/EECS , December [Cra09] Craeynest K. Van, Eyerman S., Eeckhout L., MLP-Aware Runahead Threads în a Simultaneous Multithreading Processor, Proceedings of The 4 th HiPEAC International Conference, pp , Paphos, Cyprus, January [Cul99] Culler D., Singh J., with Gupta A., Parallel Computer Architecture: A Hardware/Software Approach, Morgan Kaufmann Publishers, [Des08] Desmet V., Girbal S., Temam O., ArchExplorer.org: Joint Compiler/Hardware Exploration for Fair Comparison of Architectures, The 6-th HiPEAC Industrial Workshop, Thales, Paris, Nov. 26th, [Gab98] Gabbay F., Mendelsohn A., Using Value Prediction to Increase the Power of Speculative Execuţion Hardware, ACM Transactions on Computer Systems, vol. 16, nr. 3, [Gel09] A. Gellert, A. Florea, L. Vintan, Exploiting Selective Instruction Reuse and Value Prediction în a Superscalar Architecture, Journal of Systems Architecture, vol. 55, issue 3, Elsevier, [Gio09] Giorgi R., Popovic Z., Puzovic N., Implementing fine/medium grained TLP support în a many-core architecture, International Symposium on Systems, Architectures, Modeling and Simulation, Samos, Greece, July 20-23, [Ham04] Hammond L. et al., Transactional Memory Coherence and Consistency, The 31 st Annual International Symposium on Computer Architecture (ISCA), Munich, [Hen07] Hennessy J., Patterson D., Computer Architecture. A Quantitative Approach, 4 th Edition, Morgan Kaufmann Publishers, [HiPEAC] High-Performance Embedded Architecture and Compilation (HiPEAC) FP6/FP7 Network of Excellence, Research Challenges în High-Performance Embedded Architecture and Compilation, [Jor03] Jordan H., Alaghband G., Fundamentals of Parallel Processing, Pearson Education, Inc., Prentice Hall, [Liu08] Liu S., Gaudiot J. L., The Potential of Fine-Grained Value Prediction în Enhancing the Performance of Modern Parallel Machines, The 13 th IEEE Aşia- Pacific Computer Systems Architecture Conference (ACSAC 2008), Taiwan, August [Mar01] Martin M., et al., Correctly Implementing Value Prediction în Microprocessors that Support Multithreading or Multiprocessing, Proceedings of the 34-th Annual ACM/IEEE International Symposium on Microarchitecture, Austin, Texas, December 3-5, [Mog09] Moga A., Dubois M., A comparative evaluation of hybrid distributed shared-memory systems, Journal of Systems Architecture, vol.55, issue 1, pp , Elsevier, [Suk07] Sukhun Kang and Rakesh Kumar, Magellan: A Framework for Fast Muticore Design Space Exploration and Optimization Using Search and Machine Learning, Illinois at Urbana-Champaign, CRHC Technical Report CRHC-07-05, October 2007

264 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore [Uhr07] S. Uhrig, J. Wiese, jamuth an IP Processor Core for Embedded Java Real-Time Systems, JTRES 07 September 26-88, 2007 Vienna, Austria 17. [Vin00] Vinţan L., Arhitecturi de procesoare cu paralelism la nivelul instructiunilor (in Romanian), Editura Academiei Române, Bucureşti, [Vin07] Vinţan L., Prediction Techniques în Advanced Computing Architectures (in limba engleza), Matrix Rom Publishing House, Bucharest, 2007; [Vin08] Vinţan L., Florea A., Gellert A., Random Degrees of Unbiased Branches, Proceedings of The Romanian Academy, Series A: Mathematics, Physics, Technical Sciences, Information Science, Volume 9, Number 3, Bucharest, [Wan09] H.C. Wang, C.K. Yuen, Exploiting an abstract-machine-based framework in the design of a Java ILP processor, Journal of Systems Architecture 55 (2009) [Wat09] Watkins M., McKee S., Schaelicke L., Revisiting Cache Block Superloading, Proceedings of The 4 th HiPEAC International Conference, Paphos, Cyprus, January [Yi06] Yi J., Lilja D., Simulation of Computer Architectures: Simulators, Benchmarks, Methodologies, and Recommendations, IEEE Transactions on Computers, vol. 55, No. 3, 2006

265 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore ARHITECTURA MICROCONTROLERELOR [8] 5.1. INTRODUCERE ÎN PROBLEMATICĂ Capitolul de faţă reprezintă o descriere a familiei de microcontrollere pe 8 biţi, bazate pe arhitectura 80C51, realizate de firma Philips Semiconductors, precum şi a altor componente furnizate de către respectivul producător. Un microcontroller este un microprocesor destinat în general controlului unor procese industriale care conţine memorii şi diverse porturi de I/O integrate pe acelaşi cip. În continuare se vor prezenta modurile de adresare, setul de instrucţiuni, partajarea memoriei ş.a. în cadrul familiei de microcontrolle 80C51. Microcontrollere derivate conţin şi o interfaţă serială I 2 C (magistrală de interconectare a circuitelor integrate), care permite conectarea cu uşurinţă la peste alte 100 de componente integrate, sporind capacitatea şi funcţionalitatea microsistemului realizat. Pentru aplicaţii industriale şi automate, microcontrollerele sunt însoţite de altă o magistrală serială de control (Control Area Network - CAN). Familia de microcontrollere pe 16 biţi, 90CXXX se bazează pe arhitectura Motorola În timp ce microcontrollerele sunt pe 16 biţi în exterior, în interior unitatea centrală a arhitecturii este pe 32 de biţi. Acest fapt conferă utilizatorului o putere de procesare mai mare, în condiţiile creşterii necesităţilor de proiectare, trecând de la microcontrollere pe 8 biţi la cele pe 16 biţi. Microcontrollerele pe 16 biţi ai firmei Philips Semiconductors sunt compatibile software cu codul procesorului Motorola ARHITECTURA FAMILIEI 80C ORGANIZAREA MEMORIEI

266 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 268 Figura 5.1. Schema bloc a microprocesoarelor 80C51 Toate procesoarele 80C51 au spaţii de adrese separate pentru instrucţiuni şi date implementând deci o arhitectură de tip Harvard a memoriei (vezi figura 5.1). Accesarea zonei de date se face pe o magistrală de 8 biţi, data citită putând fi rapid memorată şi manipulată de către regiştrii pe 8 biţi ai CPU. Memoria program este de tip ROM sau EPROM şi poate avea capacităţi de până la 64ko. La dispozitivele 80C51, cei mai puţin semnificativi 4ko de memorie sunt implementaţi în cip. Memoria de date este de tip RAM. Cei mai puţin semnificativi 128 octeţi ai memoriei de date sunt implantaţi în cip, restul de până la 64ko regăsindu-se extern pe placă. Memoria program Figura 5.2 ilustrează harta memoriei program - partea cea mai puţin semnificativă. După resetarea sistemului, CPU (unitatea centrală de procesare) începe execuţia de la adresa 0000H, în conformitate cu iniţializarea PC-ului. Primii trei octeţi ai Memoriei Program pot codifica de exemplu, o instrucţiune de salt necondiţionat (JUMP <Adresă>) reprezentând prima instrucţiune care se execută imediat după iniţializare. De fapt are loc un salt la adresa de început a programului monitor program ce realizează verificarea configuraţiei hardware a microsistemului, teste de memorie, interfaţa cu utilizatorul, etc. Fiecărei întreruperi îi este asignată o locaţie fixă în memoria program. Întreruperea determină CPU să execute salt la locaţia respectivă, unde începe execuţia rutinei de serviciu (tratare a întreruperii). Zona de program aferentă rutinelor de tratare a întreruperii se împarte în intervale de 8 octeţi:

267 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore H - pentru întreruperea externă 0, 000BH - pentru circuitul Timer 0 (numărător), 0013H - pentru întreruperea externă 1, 001BH - pentru circuitul Timer 1 etc. Dacă o rutină de serviciu este suficient de scurtă, ea poate fi inclusă în interiorul unui astfel de interval de 8 octeţi. Rutinele mai lungi de opt octeţi vor folosi în general o instrucţiune de salt codificată pe maximum trei octeţi pentru a nu altera zona aferentă unei alte întreruperi active. Figura 5.2. Memoria program la procesoarele 80C51 Cei mai semnificativi 4 ko ai memoriei program pot fi implementaţi fie în cipul ROM intern fie în memoria ROM externă. Selecţia se face prin conectarea pinului EA la tensiunea de alimentare (V cc ) sau la masă (V ss ). Dacă EA este legat la V cc, accesele de citire din zona de memorie program cuprinsă între 0000H şi 0FFFH sunt direcţionate spre memoria ROM intern implementată. Accesele de citire din zona de memorie program de la adresa 1000H la FFFFH sunt îndreptate spre memoria ROM externă. Dacă EA se conectează la masă atunci toate citirile din memoria program sunt direcţionate spre memoria externă ROM. Figura 5.3 reprezintă configuraţia hardware pentru execuţia unui program stocat în memoria program externă. Se observă 16 linii de intrare / ieşire (porturile 0 şi 2) având funcţii de magistrală dedicată citirii codului (datei) din memoria program externă. Portul 0 serveşte la multiplexarea magistralei de date / adresă. Această multiplexare implică desigur o scădere a vitezei de lucru cu memoria şi este datorată unor constrângeri tehnologice

268 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 270 legate de numărul de pini ai microcontrollerului. În cadrul unui ciclu de aducere (fetch) a instrucţiunii el emite octetul cel mai puţin semnificativ al registrului Program Counter (PCL) ca şi adresă şi rămâne în stare de aşteptare până la sosirea octetului de cod din memoria program. În momentul în care octetul cel mai puţin semnificativ al registrului Program Counter este valid în portul 0, semnalul ALE (Address Latch Enable) strobează acest octet într-un latch ale cărui ieşiri atacă memoria. Între timp, portul 2 emite cel mai semnificativ octet al registrului Program Counter (PCH). În final, semnalul de validare a citirii ( PSEN ) se activează iar EPROM-ul emite octetul de cod cerut de către microcontroller, prin intermediul aceluiaşi port P0, aflat de data aceasta pe post de magistrală de date. Figura 5.3. Execuţia programelor stocate în Memoria Externă Adresarea memoriei program se face întotdeauna pe 16 biţi, chiar dacă capacitatea memoriei program fizic implementată este mai mică de 64 ko. Execuţia programelor externe sacrifică două din porturile pe 8 biţi (P0 şi P2) acordându-le acestora funcţii de adresare a memoriei program. Memoria de date În figura 5.4, se prezintă o configuraţie hardware pentru accesarea de până la 2 ko de memorie RAM externă. CPU în acest caz execută instrucţiunile din memoria ROM internă. Portul 0 serveşte ca multiplexor al magistralei de date respectiv adrese care "atacă" memoria RAM, iar cele 3 linii de intrare / ieşire ale portului 2 sunt folosite la paginarea memoriei

269 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 271 RAM (8 pagini). CPU generează semnalele de comandă RD şi WR (validare citire respectiv scriere) necesare în timpul acceselor la memoria RAM externă. Figura 5.4. Accesarea memoriei de date externă Adresarea memoriei de date externe poate fi făcută pe 8 sau 16 biţi. Adresarea pe 8 biţi este deseori folosită în conjuncţie cu una sau mai multe linii de intrare / ieşire pentru paginarea memoriei RAM. Adresarea pe 16 biţi implică folosirea portului 2 ca emitent al octetului cel mai semnificativ de adresă, aşa cum s-a mai arătat. Figura 5.5. Memoria de date internă

270 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 272 Memoria de date internă este împărţită în trei blocuri (vezi figura 5.5), referite sub numele: cei mai puţin semnificativi 128o (inferiori), cei mai semnificativi 128o (superiori), şi SFR (spaţiu alocat regiştrilor cu funcţii speciale). Adresarea memoriei de date interne se face pe cuvinte de 1 octet rezultând un spaţiu adresabil de 256o. Folosind un mic artificiu, modurile de adresare ale memoriei de date interne pot găzdui 384o şi nu doar 256o cum s-ar părea la o primă vedere. Adresarea celor 128o inferiori (00-7FH) se poate face direct sau indirect. Adresarea celor 128o superiori (80 - FFH) se face doar prin adresare indirectă iar accesul la spaţiul regiştrilor cu funcţii speciale (SFR) se face doar prin adresare directă. Rezultă că zona de 128o superiori şi spaţiul SFR ocupă acelaşi bloc de adrese, de la 80H la FFH, deşi fizic constituie două entităţi diferite. Figura 5.6 reflectă maparea celor 128o inferiori ai memoriei interne. Cei mai puţin semnificativi 32 de octeţi sunt grupaţi în 4 bancuri a câte 8 regiştri. Instrucţiunile programelor apelează aceşti regiştri sub numele R0 R7. Doi biţi din registrul de stare program (PSW) selectează bancul de regiştri folosit. Aceasta permite o eficientizare a spaţiului de cod întrucât instrucţiunile cu operare pe regiştri ocupă mai puţin spaţiu în memoria program decât instrucţiunile care folosesc adresarea directă. Următorii 16o, succesorii bancurilor de regiştri formează un bloc de memorie adresabil pe bit. Setul de instrucţiuni al microcontrollerului 80C51 cuprinde un număr mare de instrucţiuni avînd operanzi codificaţi pe un singur bit. Maparea spaţiului de memorie aferent regiştrilor cu funcţii speciale (SFR) este exemplificată în figura 5.7. De remarcat că în spaţiul alocat SFR nu toate adresele sunt ocupate. Adresele libere nu sunt implementate în cip fiind probabil rezervate pentru îmbunătăţiri ulterioare ale arhitecturii. Accesele de citire la aceste locaţii vor returna date aleatoare, iar accesele de scriere nu vor avea nici un efect. Dintre regiştrii cu funcţii speciale amintim: acumulatorul (A), registrul de stare program (PSW), pointerul de stivă (SP), pointerul de date (DPTR), registrul tampon (buffer) serial de date (SBUF), regiştrii timer, de control, de validare întreruperi, cu priorităţi de întrerupere, 4 porturi.

271 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 273 Figura 5.6. Reprezentarea celor 128 octeţi inferiori ai memoriei RAM internă Figura 1.7. Maparea spaţiului de memorie aferent regiştrilor cu funcţii speciale Registrul de stare program (vezi figura 5.8) conţine biţi de stare care reflectă starea curentă a CPU. Conţine biţii de transport - Carry, Auxiliary Carry, de depăşire - Overflow, de paritate, doi biţi de selecţie ai bancului de registre şi doi biţi de stare la dispoziţia utilizatorului. Registrul B este folosit în cadrul operaţiilor de înmulţire / împărţire. Registrul SP este pe 8 biţi şi

272 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 274 este incrementat înainte ca data să fie memorată în timpul execuţiei instrucţiunilor PUSH sau CALL (SP - pointează spre ultima locaţie ocupată din stivă). Acest lucru este atipic întrucât în majoritatea procesoarelor registrul SP este predecrementat la salvarea în stivă şi nu preincrementat ca în acest caz. Deşi stiva poate rezida oriunde în memoria RAM, registrul SP este iniţializat cu valoarea 07H imediat după semnalul Reset. Aceasta determină ca stiva să înceapă practic de la locaţia 08H. Registrul DPTR poate fi folosit ca un registru pe 16 biţi sau ca doi regiştri independenţi pe 8 biţi (DPH - octetul superior al registrului DPTR şi DPL - octetul inferior al registrului DPTR). Regiştrii pereche (TH0, TL0) şi (TH1, TL1) sunt regiştri numărători pe 16 biţi pentru circuitele timer 0 şi 1. Registrul TMOD este un registru de control şi specifică modul de lucru a celor două circuite timer. Alţi regiştri de control sunt TCON (control al circuitelor timer), SCON (control al portului serial), PCON (control al sursei de alimentare). Figura 5.8. Registrul de Stare Program (PSW) Setarea / resetarea biţilor de selecţie ai celor patru bancuri de registre (PSW 3, PSW 4 ) se face prin metode software. De exemplu: orice instrucţiune care adresează spaţiul de memorie de date 00H 1FH modifică corespunzător biţii de selecţie din PSW MODURILE DE ADRESARE Pentru aplicaţii de control pe 8 biţi, setul de instrucţiuni al microcontrollerului 80C51 a fost optimizat. Acesta permite o varietate mare

273 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 275 de moduri rapide de adresare, pentru accesarea memoriei RAM interne, facilitând operaţii pe octet asupra structurilor de date de dimensiuni reduse. Setul de instrucţiuni permite manevrarea directă a operanzilor la nivel de bit în sisteme logice şi de control care necesită procesare booleană. a. Adresare directă - operandul este specificat printr-un câmp de adresă pe 8 biţi al instrucţiunii. Doar memoria RAM internă şi SFR sunt adresabile direct. Exemplu: ADD A, 7FH ;adunare în mod de adresare direct memorie După cum s-a arătat, registrul Acumulator (adresa E0H în spaţiul SFR) aparţine zonei de memorie SFR şi poate fi adresat direct. Astfel, instrucţiunea de adunare devine: ADD E0H, 7FH şi s-ar putea crede că respectiva instrucţiune este codificată pe 3 octeţi (1 opcode-ul instrucţiunii; 2,3 cei doi operanzi [adresele de memorie]). Totuşi, respectiva instrucţiune este codificată pe doar 2 octeţi (1 opcode-ul instrucţiunii [ce include şi primul operand - acumulatorul] şi 2 al doilea operand [adresa de memorie]). De fapt, arhitectura microcontrollerului fiind orientată pe acumulator (instrucţiunile aritmetico logice cu doi operanzi au acumulatorul implicit ca sursă şi destinaţie), acesta prin excepţie faţă de ceilalţi regiştri SFR nu mai este necesar a fi adresat direct prin adresa E0H, fiind codificat în chiar opcode-ul instrucţiunii. Astfel, instrucţiunile aritmetico logice cu doi operanzi în modul de adresare direct sunt codificate pe doar doi octeţi în loc de trei. b. Adresare indirectă - adresa operandului este specificată în mod indirect prin intermediul unui registru pointer. Pentru adrese pe octet regiştrii folosiţi sunt R0 sau R1 din bancul de regiştri selectat, sau SP (stack pointer) în cazul acesării stivei. Pentru adrese pe doi octeţi se foloseşte doar registrul pointer de date (DPTR). Atât memoria RAM internă cât şi cea externă sunt adresabile indirect. Exemplu: ADD c. Adresarea prin regiştri - 3 biţi din opcode-ul instrucţiunii specifică unul din cei 8 regiştri (R0 R7) care vor fi accesaţi. Bancul de regiştri este specificat prin cei doi biţi dedicaţi ai registrului PSW în momentul execuţiei instrucţiunii. Instrucţiunile care accesează regiştrii în acest mod se numesc optimizatoare de cod întucât se elimină necesitatea unui octet de adresă (de exemplu,

274 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 276 în modul direct, adresarea R0 R7 mai consumă un octet care în plus trebuie şi adus din memoria program). Exemplu: ADD A, R7 d. Adresarea prin instrucţiuni cu regiştrii specifici - este cazul instrucţiunilor care operează asupra registrului acumulator (A) sau pointer de date (DPTR). Nu e necesar un octet de adresă pentru operanzii respectivi, codificarea operanzilor se face în chiar opcode-ul instrucţiunii. e. Adresarea prin constante imediate - folosită la încărcarea unei valori imediate într-un registru. Valorile pot fi în sistem zecimal sau hexazecimal. Exemplu: ADD A, #127 f. Adresarea indexată - este folosită la citirea tabelelor de memorie program. Doar memoria program este adresabilă indexat. Registrul DPTR sau PC reţine adresa de bază a tabelului, iar registrul acumulator reţine numărul intrării în tabel. Adresarea indexată este folosită şi în cazul instrucţiunilor de selecţie de tip "case" din limbajele de nivel înalt. În acest caz adresa instrucţiunii destinaţie se calculează ca suma dintre un pointer de bază şi acumulator. Exemplu: MOVC TIPURI DE INSTRUCŢIUNI a. Instrucţiuni aritmetice - sunt ilustrate în tabelul 5.1, împreună cu modurile de adresare aferente, timpul de execuţie, operaţia executată. Timpul de execuţie presupune o frecvenţă de ceas de 12 MHz iar instrucţiunile şi datele se presupune că sunt stocate în memoriile interne 80C51. Obs. 1. Rezultatul pe 16 biţi al înmulţirii dintre registrul B şi acumulator (A), este depus în registrul obţinut prin concatenarea registrelor B şi A. Obs. 2. Instrucţiunea DIV AB realizează împărţirea dintre A şi data din registrul B şi depune câtul în registrul A şi restul în B. Instrucţiunea DIV AB se foloseşte mai puţin în rutine matematice de împărţire decât în conversii de bază sau operaţii de deplasare (shift) - aritmetice.

275 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 277 Obs. 3. Modifică flagurile din PSW în concordanţă cu operaţia executată, astfel: adunarea, scăderea (C, OV, AC), împărţire / înmulţire (C, OV) iar celelalte instrucţiuni doar bitul C. Totodată, toate tipurile de instrucţiuni (aritmetico logice, de transfer, booleene, etc) alterează flagurile PSW 3 şi PSW 4 pentru selecţia bancului corespunzător de registre din spaţiul 00H 1FH al memoriei de date, după cum de altfel am mai arătat. Instrucţiunile aritmetice aferente microcontrollerului 80C51 Tabelul 5.1. b. Instrucţiuni logice - sunt reprezentate în tabelul 5.2. Instrucţiunile care realizează operaţii booleene (AND, OR, XOR, NOT) asupra operanzilor octeţi, execută operaţia booleană la nivel de bit. Operaţiile booleene pot fi executate asupra operanzilor octeţi în spaţiul memoriei interne de date fără a fi necesar transferul acestor operanzi în acumulator (se salvează timp şi efort necesar salvării în stivă). Obs. Modifică flagul C din PSW. Tabelul 5.2.

276 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 278 Instrucţiunile logice aferente microcontrollerului 80C51 c. Instrucţiuni de transfer date c1) din memoria de date internă Tabelul 5.3 descrie instrucţiunile care realizează transferuri de date din sau în spaţiul memoriei interne. Instrucţiunea MOV <dest>, <src> permite transferuri între oricare din spaţiile memoriei interne sau SFR fără a trece operanzii prin acumulator. La dispozitivele 80C51 stiva se află implementată în cipul memoriei RAM şi creşte de la adrese mici la adrese mari. Instrucţiunea PUSH incrementează întâi SP apoi scrie octetul în stivă iar instrucţiunea POP preia vârful stivei pentru ca mai apoi să decrementeze SP-ul. Instrucţiunile PUSH şi POP pot folosi adresarea directă pentru identificarea octetului salvat sau restaurat, dar uzual stiva este accesată prin adresare indirectă utilizând registrul pointer de stivă SP. Stiva poate ajunge până în cei 128 octeţi superiori ai memoriei RAM interne, dacă aceştia sunt implementaţi. Instrucţiunile XCH şi XCHD sunt folosite la favorizarea interschimbării datelor (reduce numărul de octeţi de cod folosiţi şi timpul de execuţie; dacă n-ar exista aceste instrucţiuni ar trebui emulate prin 3 MOVuri). Tabelul 5.3. Instrucţiunile de transfer care accesează spaţiul memoriei interne RAM Exemplu: Presupunem că registrul R0 conţine adresa 20H şi acumulatorul valoarea 3FH. La locaţia RAM internă 20H se află memorată valoarea 75H. Atunci, după execuţia instrucţiunii: XCH la locaţia 20H vom avea memorată valoarea 3FH iar acumulatorul va conţine valoarea 75H. Instrucţiunea de interschimbare prezentată poate fi înlocuită, bineînţeles în mod dezavantajos ca şi timp de execuţie, cu o secvenţă de trei instrucţiuni MOV consecutive. i. Interschimbare folosind XCH. MOV R0, #20H #75H Iniţializare regiştri

277 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 279 MOV A, #3FH XCH Realizare interschimbare ii. Interschimbare folosind trei instrucţiuni MOV. MOV R0, #20H #75H Iniţializare regiştri MOV A, #3FH MOV 30H, A (30H) A; (30H) 3FH MOV A (20H); A 75H 30H (20H) (30H); (20H) 3FH c2) din memoria de date externă Lista instrucţiunilor care accesează memoria de date externă este prezentată în tabelul 5.4. Singurul mod de adresare al memoriei de date externe este cel indirect. De observat că, în toate accesele la memoria externă de date acumulatorul este unul din operanzi (fie sursa, fie destinaţia). Semnalele de citire / scriere sunt activate doar în timpul execuţiei instrucţiunii MOVX. În mod normal, aceste semnale sunt inactive şi dacă ele nu vor fi folosite deloc, pinii aferenţi (semnalelor) sunt disponibili ca linii de intrare / ieşire suplimentari. Tabelul 5.4. Instrucţiunile de transfer care accesează spaţiul memoriei externe RAM d. Instrucţiuni de citire din tabele de căutare Tabelul 5.5 redă două instrucţiuni disponibile pentru citirea din tabele de căutare (lookup) din memoria program. Tabelele de căutare pot fi doar citite, nu şi actualizate. Tabelele pot avea până la 256 intrări (de la 0 la 255). Numărul intrării dorite este încărcat în acumulator iar adresa de început de tabel se depune în DPTR sau PC. Tabelul 5.5.

278 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 280 Instrucţiuni de citire din tabele de căutare e. Instrucţiuni booleene Dispozitivele 80C51 posedă un procesor boolean complet pe un singur bit. Tabelul 5.6 ilustrează toate instrucţiunile booleene existente (salturi condiţionate, instrucţiuni de setare, ştergere, OR, AND, complementare). În cazul instrucţiunilor de salt, adresa destinaţie este specificată printr-o etichetă sau prin adresa actuală din memoria program. Salturilor pot avea loc de la -128o la +127o în memoria program relativ la primul octet care urmează respectiva instrucţiune de salt (salturi relative). Instrucţiunile booleene la microcontrollerul 80C51 Tabelul 5.6. Exemplu: Considerăm următoarea funcţie logică ce operează asupra variabilelor booleene A, B, C, D, astfel: Q = A.B + C + /D (A and B or C or not D) Variabilele logice de intrare se vor conecta la circuit prin intermediul biţilor de la 0 la 3 ai portului P1. Bitul 0 al portului P3 reprezintă ieşirea funcţiei logice. Porturile vor fi folosite după cum urmează: Intrarea A = Bitul 0 al portului P1 (adresa 90H) vezi figura 5.7 (Maparea spaţiului de memorie aferent regiştrilor cu funcţii speciale). Intrarea B = Bitul 1 al portului P1 (adresa 91H) Intrarea C = Bitul 2 al portului P1 (adresa 92H) Intrarea D = Bitul 3 al portului P1 (adresa 93H)

279 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 281 Ieşirea Q = Bitul 0 al portului P3 (adresa B0H) Valoarea adresei X nu este specificată şi poate avea orice valoare validă din spaţiul memoriei program al microcontrollerului 80C51. Adresa Secvenţa de instrucţiuni Observaţii X MOV P1, #FFH Iniţializarea Portului P1 X+3 MOV C, P1.0 Preluarea intrării A X+5 ANL C, P1.1 A and B X+7 ORL C, P1.2 A and B or C X+9 ORL C, /P1.3 A and B or C or not D X+B MOV P3.0, C Predarea rezultatului X+D SJMP X+3 Reluarea buclă f. Instrucţiuni de salt f1) necondiţionat Tabelul 5.7 prezintă instrucţiuni de salt necondiţionat, apeluri şi reveniri din subrutină / întrerupere. Adresa de salt este specificată printr-o etichetă sau o constantă pe 16 biţi. Deşi în tabel se află o singură instrucţiune de salt JMP addr, în realitate distingem trei astfel de instrucţiuni: SJMP (adresa destinaţie este un offset relativ la adresa instrucţiunii curente) salt relativ la PC (utile în scrierea programelor relocabile) LJMP (adresa destinaţie este o constantă pe 16 biţi) salt direct AJMP (adresa destinaţie este o constantă pe 11 biţi) Instrucţiunea Call addr substituie, de asemenea, două instrucţiuni de apel: LCALL (adresa destinaţie este pe 16 biţi, rezultând că subrutina se poate afla oriunde în spaţiul de 64ko ai memoriei program) ACALL (formatul adresei destinaţie este pe 11 biţi, subrutina aflându-se în blocul de 2ko, succesor instrucţiunii de apel) Programatorul specifică asamblorului adresa subrutinei fie ca etichetă, fie ca şi constantă pe 16 biţi. Asamblorul are desigur sarcina de a stabili adresa în formatul corect cerut de instrucţiune. Diferenţa dintre instrucţiunile RET (revenire din subrutină) şi RETI (revenire din întrerupere), este aceea că RETI anunţă sistemul de control al întreruperii că întreruperea în curs s-a încheiat. Dacă nu există nici o întrerupere în curs în momentul execuţiei instrucţiunii RETI, atunci execuţia celor două instrucţiuni de revenire este identică şi constă în preluarea celor doi octeţi din vârful stivei şi încărcarea lor în PC astfel încât execuţia programului să continue din punctul din care a fost întrerupt. Instrucţiunea

280 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 282 RETI - spre deosebire de RET - permite unei întreruperi care a încercat să o întrerupă pe cea în curs şi având acelaşi nivel de prioritate, să se starteze la finele rutinei de tratare a întreruperii curente (altfel, această cerere de întrerupere nu s-ar mai lua în considerare niciodată). Cu alte cuvinte, instrucţiunea de revenire din întrerupere marchează în mod explicit finele tratării întreruperii şi permite gestionarea unor noi cereri prin resetarea bitului aferent din registrul IP (vezi în continuare, figura 5.17). Instrucţiuni de salt necondiţionat la microcontrollerul 80C51 Tabelul 5.7. f2) condiţionat Lista instrucţiunilor de salt condiţionat disponibile utilizatorului dispozitivelor 80C51 este redată de tabelul 5.8. Salturile sunt relative la adresa PC (următoare celei de salt condiţionat), într-o marjă de la o la + 127o. Adresa de salt e specificată identic ca la celelalte instrucţiuni de salt. Întrucât registrul de stare program (PSW) nu conţine un bit de Zero, instrucţiunile JZ şi JNZ testează conţinutul acumulatorului (A). Instrucţiunile DJNZ (decrementează şi execută salt dacă primul operand e diferit de zero) şi CJNE (compară operanzii şi execută salt doar dacă operanzii sunt diferiţi) au fost introduse pentru controlul buclelor de program. Instrucţiuni de salt condiţionat la microcontrollerul 80C51 Tabelul 5.8. Exemplu: Se consideră următoarea secvenţă care adaugă o întârziere într-un program, acolo unde este inserată. Regiştrii R0, R1 şi R2 reprezintă contoarele celor 3 bucle existente. Portul P1 este folosit pe post de

281 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 283 numărător binar. Valoarea adresei X nu este specificată şi poate avea orice valoare validă din spaţiul memoriei program al microcontrollerului 80C51. Adresa Secvenţa de Observaţii instrucţiuni X INC P1 Se incrementează numărătorul binar X+2 MOV R0, #02H Setează prima constantă de întârziere X+4 MOV R1, #FFH Setează a doua constantă de întârziere X+6 MOV R2, #FFH Setează a treia constantă de întârziere X+8 DJNZ R2, X+8 Decremetează R2 şi execută salt la adresa specificată dacă R2 0 X+A DJNZ R1, X+4 Decremetează R1 şi execută salt la adresa specificată dacă R1 0 X+C DJNZ R0, X+2 Decremetează R0 şi execută salt la adresa specificată dacă R0 0 X+E SJMP X Reluarea buclă ARHITECTURA INTERNĂ Figura 5.9 prezintă schema bloc de principiu a microcontrollerelor 80C51. Toate resursele interne sunt centrate în jurul unei magistrale care permite schimbul de date practic între toate modulele componente (ROM, RAM, porturi I/O, ACC, SFR, SP etc.). Astfel de exemplu, în cazul unei operaţii de adunare operanzii sursă sunt înscrişi în regiştrii temporari TMP1,2 (invizibili pentru programator) iar rezultatul este depus pe magistrala centrală de unde apoi este înscris în registrul destinaţie (de obicei în acumulator). Memoriile ROM şi RAM sunt adresate prin regiştri de adrese special dedicaţi, desigur invizibili pentru programator. Toate resursele sunt comandate de către o unitate de control care are relul de a genera secvenţiat în timp toate semnalele de comandă interne sau externe necesare desfăşurării operaţiilor efectuate de către microcontroller (aducere instrucţiuni / date, scriere rezultate, decodificări instrucţiuni, achitare întreruperi etc.). Registrul de instrucţiuni, destinaţia implicită a oricărui ciclu de aducere instrucţiune, este inclus şi el în această unitate de comandă.

282 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 284 Figura 5.9. Arhitectura 80C51. Schema internă Sursa de ceas a unităţii centrale Toate microcontrollerele familiei 80C51 au încorporate în cip un oscilator (circuit basculant astabil), care poate fi folosit dacă se doreşte, ca sursă de semnal de ceas pentru CPU. În acest sens, se conectează cristalul de cuarţ sau ceramica între pinii XTAL1 şi XTAL2 ai microcontrollerului, şi capacităţile condensatorilor la masă (vezi figura 5.10). Figura 5.11 conţine exemple de utilizare şi a semnalelor de ceas extern pentru microcontroller. La dispozitivele NMOS, semnalele de la pinul XTAL2 devine generatorul

283 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 285 de ceas intern. La dispozitivele CMOS, semnalul primit la pinul XTAL1 reprezintă sursa de ceas CPU. Figura Utilizarea unui oscilator implantat în cip drept sursă de ceas Figura Folosirea unei surse de ceas externe pentru CPU Accesarea memoriei externe Distingem două tipuri de accese la memoria externă: accese la memoria program externă (vezi figura 5.12) şi accese la memoria de date externă (vezi figurile 5.13 şi 5.14). Orice ciclu de acces se constituie dintr-o secvenţă de 6 stări, fiecare împărţită în 2 perioade de tact (P1, P2).

284 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 286 Figura Extragerea instrucţiunilor din memoria program externă Figura Ciclul de citire din memoria de date externă

285 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 287 Figura Ciclul de scriere în memoria de date externă Semnalul de validare a citirii instrucţiunilor din memoria program este PSEN (program store enable). Instrucţiunea se citeşte efectiv sincron cu un front al ceasului, în ultima parte a intervalului în care semnalul PSEN este activ, perioadă în care portul P0 îndeplineşte funcţia de magistrală de intrare date şi nu de magistrală de adrese ca până în acest interval. Accesele la memoria de date externă folosesc semnalele RD sau WR (funcţii alternate ale pinilor 6 şi 7 ai portului P3) pentru a valida citirea / scrierea datelor. Şi în acest caz, perioada de activare a acestor două semnale determină schimbarea funcţiei portului P0 din port de adrese în port de date (prin multiplexare). Desigur că această multiplexare în timp a funcţiilor portului P0 (adrese date) are repercursiuni negative asupra vitezei de transfer a microcontrollerului. Adresarea memoriei externe de program se face întotdeauna pe 16 biţi, în timp ce, memoria externă de date poate fi adresată fie pe 16 biţi (MOVX fie pe 8 biţi (MOVX La adresarea pe 16 biţi, octetul superior de adresă este furnizat de portul P2 şi este reţinut de acesta pe toată durata ciclului de citire sau scriere. În cazul adresării pe 8 biţi, conţinutul portului P2 rămâne disponibil la pinii acestuia pe toată durata ciclului de citire / scriere a memoriei, una sau mai multe din liniile de intrare / ieşire fiind folosite în conjuncţie cu octetul de adresă furnizat de portul P0, facilitând paginarea memoriei. În ambele cazuri, octetul inferior de adresă e furnizat temporar de către portul P0. Semnalul ALE (adrress latch enable) trebuie să memoreze octetul de adresă într-un latch extern, întrucât în

286 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 288 continuare el îşi va schimba funcţia în magistrală de date. Octetul de adresă devine valid la tranziţia negativă a semnalului ALE, când va fi memorat în acel registru extern. În cazul ciclului de scriere, octetul de date ce va fi scris va fi disponibil în portul P0 înainte de activarea semnalului WR şi rămâne astfel până la dezactivarea respectivului semnal. În ciclul de citire, octetul de date citit este acceptat în portul P0 chiar înainte ca semnalul RD să fie dezactivat. Reamintim că pentru accesarea memoriei program externe este necesară cel puţin una din condiţiile: 1 semnalul EA este activ sau 2 registrul PC conţine o valoare mai mare decât 0FFFH. Când CPU execută programe nesituate în memoria program externă, toţi cei 8 biţi ai portului P2 au funcţii dedicate de ieşire şi nu pot fi folosite drept linii de intrare / ieşire. În timpul extragerii de instrucţiuni din memoria program externă, portul P2 va conţine octetul superior al PC. Structura de întreruperi Microcontrollerele din familia 80C51 precum şi cele realizate, folosind sau nu, circuite ROM sau EPROM au cinci surse de întrerupere: 2 întreruperi externe, 2 întreruperi de timer şi întreruperea pe port serial (vezi figura 5.15). Figura Sursele de întrerupere aferente microcontrollerului 80C51

287 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 289 Cele cinci surse de întrerupere sunt interne şi respectiv externe. Cele 3 întreruperi endogene sunt prezentate succint în continuare. Prima ar fi cea de emisie-recepţie serială, adică P3.0 = R x D ( întrerupere la recepţia serială de date, deci buffer de recepţie plin ) sau P3.1 = T x D (întrerupere la transmisia serială de date, deci buffer de emisie gol ). Diferenţierea între întreruperea de emisie şi cea de recepţie se face doar în cadrul rutinei de tratare prin examinarea unui registru de control care specifică explicit cauza întreruperii (bit TI=1 sau/şi bit RI=1). În general, în caz de conflict, se dă prioritate întreruperii de recepţie. Celelalte 2 întreruperi interne ar fi cele provocate de timerele interne comandate cu ceas prin pinii: P3.4 = T0 (întreruperea de timer 0 - depăşire) şi P3.5 = T1 (întreruperea de timer 1 - depăşire). Celelalte 2 întreruperi sunt de natură exogenă şi anume: pe pinul P3.2 = INT0 (întreruperea externă 0), pe pinul P3.3 = INT1 (întreruperea externă 1). Validarea sau invalidarea surselor de întrerupere poate fi făcută individual prin setarea sau ştergerea unui bit în registrul IE (interrupt enable) din SFR. Registrul respectiv conţine, de asemenea, un bit de dezactivare globală care şters, poate dezactiva toate sursele de întrerupere în acel moment (vezi figura 5.16). Figura Registrul de validare al întreruperii (IE) Priorităţile de întrerupere Fiecare sursă de întrerupere poate fi în mod individual programată pe unul din cele două nivele de prioritate existente, prin setarea sau ştergerea unui bit într-unul din regiştrii SFR numit IP (interrupt priority) - vezi figura Rutina aferentă unui nivel de prioritate scăzut (low) poate fi întreruptă

288 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 290 de către un nivel de prioritate ridicat (high), dar nu de către un nivel de prioritate scăzut. Un nivel de prioritate ridicat al unei întreruperi nu poate fi întrerupt de nici una din sursele de întrerupere, pe nici un nivel de prioritate. Dacă două întreruperi, fiecare fiind caracterizate de nivele de prioritate diferite, sunt recepţionate simultan, cea cu nivelul de prioritate ridicat este deservită mai întâi. În cazul în care, cele două întreruperi sunt la acelaşi nivel de prioritate şi sunt recepţionate simultan, o secvenţă internă de interogare (polling) va determina care întrerupere va fi deservită prioritar. Astfel, în cadrul fiecărui nivel de prioritate (0 sau 1) există o structură de priorităţi secundară, determinată de secvenţa de interogare (polling), după cum urmează (vezi tabelul 5.9): Sursa IE0 TF0. IE1. Prioritatea în cadrul nivelului Cea mai ridicată (prioritară) TF1. RI+TI Cea mai joasă (mai puţin prioritară) Tabelul 5.9. Structura secundară de priorităţi de întrerupere IE1 / IE0 reprezintă al doilea / al patrulea bit al registrului TCON (registru de control al circuitelor timer). Sunt setaţi de hardware la detecţia unei întreruperi externe. Sunt resetaţi după tratarea întreruperii. TF1 / TF0 reprezintă cel mai semnificativ / al şaselea bit al registrului TCON. Sunt setaţi de hardware la realizarea unei operaţii de depăşire (overflow) de către circuitele timer 1 sau 0. Sunt resetaţi prin hardware când se trece la execuţia rutinei de tratare a întreruperii. TI reprezintă flagul de întrerupere pe transmisie de date. Este setat de hardware la sfârşitul transmisiei celui de-al 8-lea bit de date (buffer emisie gol ), în modul 0 de lucru al portului serial sau la începutul transmisiei bitului de STOP în celelalte moduri de lucru, în orice transmisie serială. Trebuie resetat prin software. RI reprezintă flagul de întrerupere pe recepţie de date şi la fel ca TI aparţin registrului SCON (registrul de control al portului serial). Este setat de hardware la sfârşitul recepţionării celui de-al 8- lea bit de date (buffer recepţie plin ), în modul 0 de lucru al portului serial sau la jumătatea trnsmisiei bitului de STOP în celelalte moduri de lucru, în orice recepţie serială. Trebuie resetat prin software.

289 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 291 Exemplu: Dacă flagul de validare a întreruperii este setat pe 1 în registrul IE (interrupt enable), sistemul de întreruperi generează un apel LCALL la locaţia corespunzătoare în memoria program după activarea întreruperii şi doar dacă alte condiţii nu inhibă întreruperea. Există câteva condiţii de blocare a unei întreruperi dintre care o amintim pe aceea că o întrerupere de prioritate mai mare sau egală se află în progres în acel moment. Instrucţiunea LCALL, generată practic prin hardware, determină depunerea conţinutului registrului PC (program counter) pe stivă şi încărcarea registrului PC cu adresa de început a rutinei de serviciu (tratare a întreruperii). Reamintim că, rutinele de serviciu ale fiecărei întreruperi încep la locaţii fixate în memoria program (vezi figura 5.2). Doar registrul PC este salvat automat în stivă, nu şi PSW sau orice alt registru. Acest lucru permite programatorului să decidă cât timp să aloce salvării altor regiştri funcţie de numărul regiştrilor ce trebuie salvaţi (cei alteraţi de către rutina de tratare a întreruperii). Aceasta determină reducerea timpului de răspuns al întreruperilor, programatorul acţionând direct asupra acestui parametru. Ca rezultat, multe funcţii de întrerupere, care se regăsesc în aplicaţii de control, cum ar fi: complementarea, alternanţa (toggling) unui pin aferent porturilor, reîncărcarea unui numărător (timer), descărcarea unui buffer serial etc. pot fi deseori realizate într-un timp mult mai scurt decât cel necesar realizării respectivelor funcţii de întrerupere pe alte arhitecturi. Figura Registrul cu nivele de priorităţi de întrerupere (IP)

290 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 292 Simularea unui al treilea nivel de întrerupere în software Unele aplicaţii necesită mai mult decât cele două nivele de prioritate care sunt implementate prin hardware în cip la microcontrollerele 80C51. În acest caz se realizează aplicaţii software simple care au acelaşi efect ca şi un al treilea nivel de prioritate al unei întreruperi. Pentru asta, mai întâi, întreruperii care urmează să aibă prioritatea mai mare decât 1 i se asignează prioritatea 1 în registrul IP (interrupt priority). Rutina de tratare pentru întreruperea de prioritate 1, care se presupune posibil a fi întreruptă de întreruperea cu prioritate 2, este scrisă incluzându-se şi următorul cod: LABEL: PUSH IE MOV IE, #MASK ;validează exclusiv întreruperea de nivel 2 în IE. CALL LABEL *************************************************** (Execuţia rutinei de serviciu aferentă întreruperii cu nivelul 1 de prioritate. Aceasta poate fi întreruptă de o întrerupere de nivel 2!) ***************************************************** POP IE RET RETI De îndată ce sunt cunoscute toate priorităţile de întrerupere, registrul de validare a întreruperii (IE) este redefinit pentru a dezactiva toate sursele de întrerupere mai puţin cea de prioritate 2. Apoi, prin apelul CALL la eticheta LABEL, se execută instrucţiunea RETI, care încheie (eliberează) întreruperea de prioritate 1, aflată în progres (RETI spune sistemului de control al întreruperii că întreruperea aflată în progres s-a încheiat şi prin urmare permite după execuţie luarea în considerare a întreruperii de nivel 2 pe parcursul execuţiei rutinei de tratare aferente întreruperii de nivel 1). În acest moment, orice întrerupere de prioritate 1 care este validată poate fi deservită, însă doar întreruperea de prioritate 2 este validată. După execuţia rutinei de serviciu aferentă întreruperii de prioritate 2, care poate fi tratată oriunde în memoria program, are loc restaurarea registrului IE din stivă cu octetul original de validare a întreruperilor. Apoi, instrucţiunea RET este folosită pentru a încheia rutina de serviciu aferentă întreruperii de prioritate 1, cea iniţială.

291 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore STRUCTURA INTERFEŢELOR DE INTRARE / IEŞIRE Microcontrollerele, spre deosebire de microprocesoare, se caracterizează prin includerea în propriul cip a diverselor porturi de I/O seriale şi paralele, a circuitelor timer, memorii, sursă de ceas internă, etc. În compensaţie, structura şi filosofia lor de funcţionare sunt mai simple, adaptate la cerinţele controlului diverselor procese industriale. Structura porturilor Toate cele patru porturi ale microcontrollerului 80C51 sunt bidirecţionale. Fiecare constă dintr-un latch (P0 P3) registre din spaţiul SFR, un driver de ieşire şi un buffer de intrare. Scrierea unui 1 respectiv 0 într-un bit al oricărui port SFR (P0, P1, P2 sau P3) determină comutarea pinului de ieşire al portului corespondent în stare high respectiv low. Driverele de ieşire ale porturilor P0 şi P2, şi bufferul de intrare al portului P0 sunt folosite în accese la memoria externă. Aşa cum s-a mai arătat, portul P0 emite octetul inferior de adresă necesar adresării memoriei externe, multiplexat cu octetul de date ce va fi scris sau citit. Portul P2 emite octetul superior de adresă către memoria externă, în cazul adresării pe 16 biţi. Altfel portul P2 indică conţinutul registrului din spaţiul SFR. Toţi pinii portului P3 sunt multifuncţionali. Aceştia nu sunt doar pini ai portului 3 ci servesc şi la realizarea a diverse funcţii (vezi tabelul 5.10). Pinii portului P3 Funcţia alternativă P3.0 R x D (intrare serială a portului) P3.1 T x D (ieşire serială a portului) P3.2 INT0 (întreruperea externă 0) P3.3 INT1 (întreruperea externă 1) P3.4 T0 (intrarea externă a circuitului Timer 0) P3.5 T1 (intrarea externă a circuitului Timer 1) P3.6 WR (semnal de strobare la scrierea octetului de date în memoria externă) P3.7 RD (semnal de strobare la citirea datelor din memoria externă) Tabelul Funcţiile alternative ale pinilor portului P3

292 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 294 Funcţiile alternative pot fi activate doar dacă bitul din latch-ul corespondent din SFR este 1. Rolul driverelor de ieşire ale porturilor P0 şi P2 poate comuta între magistrală de adresă a memoriei interne (ADDR) şi rol de magistrală de adresă / date în cazul acceselor la memoria externă. În timpul acceselor la memoria externă, registrul P2 din SFR rămâne nemodificat, dar în registrul P0 din SFR este înscrisă valoarea 1. Fiecare linie de I/O poate fi folosită în mod independent atât ca intrare cât şi ca ieşire. Porturile P0 şi P2 nu pot fi folosite ca şi registre de uz general de I/O atunci când sunt folosite în operaţii de accesare a memoriei externe. Toate latch-urile microcontrollerului 80C51 sunt iniţializate cu valoarea 0FFH de către funcţia Reset. Dacă într-un latch al unui port se scrie ulterior un 0, portul poate fi reconfigurat ca intrare prin scrierea unui 1 în latchul portului respectiv. Scrierea în porturi e ilustrată în figura 5.18 fiind similară cu accesele la memorii prezentate anterior. Figura Scrierea în porturi În execuţia unei instrucţiuni care modifică valoarea într-un latch al porturilor, noua valoare e memorată în latch în timpul fazei a doua din starea şase a ciclului final al instrucţiunii (S6P2). Totuşi, conţinutul latchurilor sunt disponibile la bufferele lor de ieşire doar în timpul fazei întâi a perioadei de tact iar în timpul fazei a doua bufferul de ieşire reţine valoarea respectivă. În consecinţă, noua valoare în latchul portului nu va apărea la pinul de ieşire până în următoarea fază P1 din ciclul maşină următor scrierii în port (S1P1). Dintre instrucţiunile care citesc un port distingem instrucţiuni care citesc portul propriu zis şi respectiv instrucţiuni care citesc pinii aferenţi portului. Instrucţiunile care citesc porturi se caracterizează prin faptul că

293 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 295 citesc o valoare, o modifică posibil, şi apoi o rescriu în port. Operandul destinaţie poate fi un port sau un bit al portului respectiv. Aceste instrucţiuni se numesc instrucţiuni citeşte modifică scrie (read-modify-write). În continuare prezentăm câteva astfel de instrucţiuni: Instrucţiunea ANL P1, A ORL P2, A XRL P3, A JBC P1.1, Label CPL P3.0 INC P2 DEC P2 DJNZ P3, Label MOV Px.y, C CLR Px.y SET Px.y Operaţia executată P1 ŞI LOGIC A (Acumulatorul) P2 SAU LOGIC A P3 XOR LOGIC A Dacă P1.1 = 1 execută salt şi resetează bitul Complementează respectivul bit Incrementează latchul portului P2 Decrementează latchul portului P2 Decrementează P3 şi execută salt dacă P3<>0 Transferă bitul Carry la bitul y al portului x Resetează bitul y al portului x Setează bitul y al portului x Tabelul Instrucţiuni de scriere în porturi Deşi nu sunt evidente, ultimele trei instrucţiuni sunt de tipul citeşte modifică scrie. Acestea citesc octetul de date al portului (toţi cei 8 biţi), modifică bitul adresat şi apoi scrii noul octet în port. Motivul pentru care instrucţiunile de tipul citeşte modifică scrie sunt direcţionate mai mult către porturi decât către pini constă în evitarea unei posibile interpretări greşite a nivelului electric al pinilor. De exemplu, se consideră că un bit al unui port este folosit la comanda bazei unui tranzistor. Când acest bit este setat pe 1 tranzistorul este pornit. Dacă CPU citeşte apoi acelaşi bit al portului la nivel de pin, acesta va citi tensiunea de bază a tranzistorului şi va fi interpretată ca 0. Citind acelaşi bit din latchul aferent portului respectiv, vom avea valoarea corectă, şi anume 1. Interfaţa serială standard Portul serial este de tip full duplex, ceea ce înseamnă că poate emite şi recepţiona date simultan. Regiştrii de emisie recepţie ai portului serial sunt accesaţi prin registrul SBUF din spaţiul SFR. Bufferul serial constă de fapt din două registre separate, un buffer de emisie şi unul de recepţie. Când o dată este depusă în SBUF, ea e direcţionată spre bufferul de emisie şi reţinută pentru transmisie serială. Când o dată este mutată din

294 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 296 SBUF aceasta provine din bufferul de reepţie. Portul serial poate opera în patru moduri asincrone: a. Modul 0. Intrarea şi ieşirea serială se face pe linia R x D. La ieşirea T x D vom avea linia de ceas. Sunt transmişi / recepţionaţi 8 biţi de date, începând cu cel mai puţin semnificativ (LSB). Rata de transfer a datelor (exprimată în baud) este fixată la 1/12 din frecvenţa de oscilaţie a generatorului de tact. b. Modul 1. Sunt transmişi 10 biţi (pe linia T x D) sau recepţionaţi (pe linia R x D), în formatul asincron: un bit de start (0), 8 biţi de date (cel mai puţin semnificativ - primul) şi un bit de stop (1). La recepţie, bitul de stop e înscris în RB8, bit aparţinând registrului SCON (vezi figura 5.19). Rata de transfer este variabilă, funcţie de frecvenţa de tact. c. Modul 2. Sunt transmişi (pe linia T x D) sau recepţionaţi (pe linia R x D) 11 biţi: bitul de start (0), 8 biţi de date (primul LSB), un bit programabil (al 9-lea bit de date) şi un bit de stop (1). La transmisia datelor, celui de-al 9-lea bit de date (bitul TB8 din SCON vezi figura 1.19) îi poate fi asignată valoarea 0 sau 1. La recepţie, cel de-al 9-lea bit este înscris în RB8 al SCON, iar bitul de stop este ignorat. Rata de transfer este programabilă fie la 1/32 fie la 1/64 din frecvenţa de oscilaţie a generatorului de tact. d. Modul 3. Este identic cu modul 2 de operare, exceptând rata de transfer. În modul 3, rata de transfer este variabilă. Util în comunicaţia multiprocesor după cum se va arăta în continuare. În toate cele patru moduri transmisia este iniţiată de către orice instrucţiune care foloseşte registrul SBUF (buffer de emisie) ca destinaţie. Recepţia este iniţiată în modul 0 de către condiţiile (RI=0) AND (REN=1). Recepţia este iniţiată, în celelalte moduri, clasic pentru protocoalele asincrone, de către sosirea bitului de start dacă REN=1. Registrul de stare şi control al portului serial SCON (vezi figura 5.19) conţine nu doar biţii de selecţie ai modului de operare ci şi al 9-lea bit de date dintr-o transmisie sau recepţie (TB8 şi RB8), şi biţii de întrerupere ai portului serial (TI şi RI).

295 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 297 Figura Registru de control al portului serial (SCON) Comunicaţia în sisteme multiprocesor Modurile de operare 2 şi 3 tratează special comunicaţia în sisteme multiprocesor. În aceste moduri, sunt recepţionaţi 9 biţi de date. Cel de-al 9- lea bit este memorat în RB8 al registrului SCON. Apoi urmează bitul de STOP. Portul poate fi programat astfel încât, la recepţionarea bitului de stop, întreruperea de port serial va fi activată doar dacă RB8=1. Caracteristica de comunicaţie multiprocesor e validată dacă bitul SM2 din SCON este setat. O modalitate de a folosi respectiva caracteristică în sisteme multiprocesor este următoarea: Când un procesor master doreşte să transmită un bloc de date unuia din dispozitivele slave, acesta trimite mai întâi un cuvânt de adresă care identifică slave-ul destinaţie. Un cuvânt de adresă diferă de unul de date prin aceea că al 9-lea bit este 1 în cuvântul de adresă şi 0 în cel de date. Când SM2=1, nici un slave nu va fi întrerupt de către un octet de date. Un cuvânt de adresă, totuşi, va întrerupe toate dispozitivele slave, astfel încât fiecare slave să poată examina şi detecta dacă cuvântul recepţionat reprezintă adresa sa. Slave-ul adresat va reseta bitul SM2 şi se va pregăti să recepţioneze cuvântul de date. Dispozitivele slave care nu au fost adresate lasă biţii SM2 aferenţi lor setaţi şi îşi continuă activitatea neperturbate, ignorând cuvântul de date. SM2 nu are nici un efect în modul 0, iar în modul 1 poate fi folosit să verifice validitatea bitului de stop. În recepţia din modul 1, dacă SM2=1, întreruperea de recepţie nu va fi activată dacă nu se recepţionează un bit de stop valid.

296 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 298 Circuite Timer/Numărătoare Microcontrollerul 80C51 conţine două registre timere/numărătoare pe 16 biţi: Timer 0 şi Timer 1. Ambele pot fi configurate să opereze atât ca circuite timer (periodizatoare) cât şi ca numărătoare. Având funcţia de timer, registrul este incrementat cu fiecare ciclu maşină. Întrucât un ciclu maşină constă din 12 perioade de oscilaţie ale generatorului de tact, rata de numărare este 1/12 din frecvenţa oscilatorului. Având funcţia de numărător, registrul este incrementat ca răspuns la o tranziţie din 1 în 0 a intrării externe corespondente de la pinul T 0 sau T 1. Noua valoare numerică apare în registru în timpul fazei P1 a ciclului (S3P1) următor celui în care s-a detectat tranziţia. Întrucât durează doi cicli maşină (24 perioade de oscilaţie) pentru a recunoaşte o tranziţie din 1 în 0, rata maximă de numărare este 1/24 din frecvenţa oscilatorului. Pe lângă posibilitatea de selecţie între funcţia de timer sau numărător, circuitele Timer0 şi Timer1 sunt caracterizate de patru moduri de operare. Funcţia de timer sau numărător este selectată cu ajutorul biţilor C/T din registrul TMOD din spaţiul SFR (vezi figura 5.20). Biţii M1 şi M0, aparţinând aceluiaşi registru TMOD, selecteaz modul de operare. Modurile 0, 1 şi 2 sunt aceleaşi atât pentru Timer/Numărătorul 0 cât şi pentru Timer/Numărătorul 1. Modul 3 este diferit funcţie de circuit. Figura Registrul de control al modului de funcţionare al circuitelor Timer (TMOD)

297 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 299 a. Circuitele Timer în modul 0 se comportă precum circuitul Timer 8048, care este un numărător pe 8 biţi. În acest mod registrul timer este configurat ca un registru pe 13 biţi. Dacă numărul existent în registru devine din toţi biţii pe 1 în toţi biţii pe 0, este setat flagul de întrerupere pe Timerul1 (TF1). Intrarea de numărare este validată când TR1=1 şi, fie GATE=0 fie INT1 =1. Setând GATE pe 1 se permite timerului să fie controlat de intrarea externă INT1, facilitând măsurarea perioadei de tact. TR1 este un bit de control din registrul TCON aparţinând SFR (vezi figura 1.21). GATE aparţine registrului SMOD. Cei 13 biţi ai registrului constau din 8 biţi din TH1 şi 5 biţi din TL1. Cei 3 biţi superiori ai TL1 sunt nedeterminaţi şi trebuie ignoraţi. Setarea flagului de execuţie (TR1) nu resetează conţinutul registrului timer. b. Modul 1 este identic cu modul 0, exceptând faptul că registrul timer rulează cu toţi cei 16 biţi ai săi. c. Modul 2 configurează registrul timer ca un numărător pe 8 biţi (TL1) cu reîncărcare automată. Depăşirea din TL1 nu doar setează TF1 dar şi reîncarcătl1 cu conţinutul lui TH1, care este presetat software. Reîncărcarea lasă TH1 nemodificat. Modul 2 operează în acelaşi mod şi asupra Timerului/Numărătorului 0. d. În modul 3 Timerul 1 reţine numărul. Efectul este identic cu setarea TR1 pe 0. Timerul 0 în modul3 identifică pe TL0 şi TH0 ca două numărătoare separate. TL0 utilizează biţii de control ai Timerului 0: C/T, GATE, TR0, INT0 şi TF0. TH0 este fixat (blocat) într-o funcţie timer (numărare a ciclilor maşină) ce are ca argumente pe TR1 şi TF1 din Timerul1. Astfel, TH0 controlează şi întreruperea de Timer 1. Modul 3 este furnizat pentru aplicaţii care necesită timere/numărătoare ce depăşesc 8 biţi. Cu Timerul 0 în modul 3 de operare, microcontrollerul 80C51 simulează trei timere/numărătoare. Când Timerul 0 este în modul 3, Timerul 1 poate fi pornit/oprit prin comutarea sa în/din modul 3, sau poate fi folosit de către portul serial ca generator de rate de transfer, sau în orice aplicaţie care nu necesită o întrerupere.

298 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 300 Figura Registrul de control al cicuitelor Timer/Numărător (TCON) 5.4. MAGISTRALA DE INTERCONECTARE I 2 C I 2 C, magistrală bidirecţională pe două fire, a fost dezvoltată de către compania Philips, pentru eficientizarea (maximizarea performanţei hardware şi respectiv simplitatea circuitelor) controlului interconectării circuitelor. Toate dispozitivele compatibile cu magistrala I 2 C conţin o interfaţă implementată în cip care permite tuturor dispozitivelor de acest gen să comunice între ele prin respectiva magistrală. Acest concept de proiectare rezolvă multe probleme de interfaţare ce apar în proiectarea circuitelor de control digital. El se remarcă prin simplitate şi eficienţă, caracteristici deosebit de apreciate în controlul industrial al proceselor tehnologice. Caracteristicile magistralei de interconectare Necesită doar două linii de magistrală (o linie serială de date SDA, şi o linie serială de ceas SCL). Fiecare dispozitiv conectat la magistrală este software adresabil printr-o adresă unică şi în fiecare moment există o relaţie simplă de tip master / slave. Este o magistrală multimaster care include detecţia coliziunilor şi arbitrarea acestora pentru a preveni inconsistenţa datelor în cazul în care

299 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 301 două sau mai multe dispozitive master iniţiază simultan transferul de date. Pe magistrala serială de date, pe 8 biţi, au loc transferuri bidirecţionale de date cu viteze până la 100kbit / s în mod standard sau până la 400kbit / s în mod rapid (fast). Filtrele implementate în cip elimină zgomotele datorate diafoniilor, reflexiilor, etc (spike-uri) de pe linia de date pentru păstrarea integrităţii datelor. Numărul de circuite care pot fi conectate la aceeaşi magistrală este limitat doar de capacitatea maximă a respectivei magistrale, anume de 400pF. Avantajele proiectantului constau în facilitatea oferită de circuitele integrate interconectate prin magistrala I 2 C, privind trecerea rapidă de la organigrama cu blocuri funcţionale la prototip. Circuitele integrate (IC Integrated Circuits) sunt conectate la magistrala I 2 C fără o interfaţă suplimentară externă, permiţând modificarea sau îmbogăţirea sistemului prototip simplu prin conectarea sau deconectarea de la magistrală (sisteme de dezvoltare). Figura Aplicaţii utilizând magistrala I 2 C

300 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 302 Figura 5.22 ilustrează în mod intuitiv două aplicaţii utilizând magistrala de interconectare I 2 C. Caracteristicile circuitelor integrate compatibile cu magistrala I 2 C Blocurile funcţionale din organigramă corespund cu circuitele integrate actuale. Nu este necesară proiectarea interfeţei la magistrală deoarece interfaţa I 2 C este deja integrată în cip. Adresarea integrată şi protocolul de transfer de date permite sistemului să fie definit complet din punct de vedere software. Aceleaşi tipuri de IC - uri pot fi des folosite în mai multe aplicaţii diferite. Timpul de proiectare reduce durata procesului de familiarizare a proiectantului cu cele mai frecvent folosite blocuri funcţionale, reprezentate de circuitele integrate compatibile cu magistrala I 2 C. Circuitele integrate pot fi adăugate sau înlăturate din sistem fără a afecta celelalte circuite conectate la magistrală ( aşadar caracteristici de modularizare şi toleranţă la defectări). Depanarea disfuncţiunilor se poate realiza pas cu pas. Timpul de dezvoltare software poate fi redus prin asamblarea unor biblioteci cuprinzând module software refolosibile. Circuitele integrate compatibile cu magistrala I 2 C, de tip CMOS, oferă proiectantului proprietăţi speciale, atractive pentru echipamentele portabile şi sistemele alimentate de baterie. Ele se caracterizează prin: Consum redus de energie electrică. Imunitate ridicată la zgomot. Suportă variaţii largi de tensiune. Suportă variaţii mari de temperatură. Avantajele fabricantului de circuite integrate compatibile cu magistrala I 2 C Magistrala I 2 C este compusă din două fire simple, fapt ce minimizează interconexiunile şi fac ca circuitele integrate să aibă un număr redus de pini. Protocolul de magistrală I 2 C elimină necesitatea unui decodor de adrese. Capacitatea de multimaster a magistralei I 2 C permite testarea rapidă şi alinierea echipamentului utilizatorului prin conexiuni externe la un computer printr-un program ( eventual scris în asamblare). caracteristică a magistralei I 2 C, apreciată atât de către proiectanţi cât şi de către fabricanţi, este aceea că, natura simplă, bazată pe doar două fire şi

301 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 303 capabilitatea adresării software, fac din I 2 C o platformă ideală pentru magistrala ACCESS.bus (vezi figura 5.27). Aceasta reprezintă o alternativă, din punct de vedere cost / performanţă, pentru interfaţa RS 232C de conectare a perifericelor la un calculator gazdă printr-un conector simplu având patru pini. Specificaţii privind magistrala I 2 C Pentru aplicaţii de control digital pe 8 biţi, cum sunt cele care necesită microcontrollere, se stabilesc criterii principiale de proiectare, astfel: Un sistem complet constă, de regulă, din cel puţin un microcontroller, memorii şi alte dispozitive periferice cum ar fi extensiile de porturi de intrare / ieşire. Costul interconectării diverselor dispozitive trebuie să fie minim. Un sistem care execută o funcţie de control nu necesită un transfer rapid de date. Eficienţa globală depinde de dispozitivele alese şi de natura structurii magistralei de interconectare. Pentru realizarea unui sistem care să satisfacă aceste criterii, este nevoie de o structură de magistrală serială. Deşi, magistralele seriale nu au aceleaşi capabilităţi ca cele paralele, ele necesită mai puţine fire şi mai puţini pini din partea circuitelor integrate ce se vor conecta. O magistrală însă, nu reprezintă numai nişte sârme de interconectare, ci întruchipează toate formatele şi procedurile de comunicare din interiorul sistemului. Comunicaţiile între dispozitive prin intermediul magistralei I 2 C trebuie realizate prin protocoale clar definite şi complete, pentru a se evita toate posibilităţile de confuzie, pierderi de date şi blocaje informaţionale. Dispozitivele rapide trebuie să poată comunica cu dispozitivele lente. Sistemul nu trebuie să fie dependent de dispozitivele conectate la el, altfel nu ar fi posibile eventuale modificări şi îmbunătăţiri. O procedură trebuie să decidă care dispozitiv va controla magistrala, şi când. În cazul interconectării dispozitivelor cu rate de ceas diferite, trebuie specificat sursa semnalului de ceas al magistralei. Conceptul de magistrală de interconectare Cele două fire (SDA - date şi SCL - ceas) transportă informaţie între dispozitivele conectate la magistrală. Fiecare dispozitiv este caracterizat de o adresă unică dacă este microcontroller, driver LCD, memorie, interfaţă pentru tastatură şi pot opera fie ca emiţător fie ca receptor, dependentă de funcţia dispozitivului. Evident că un driver LCD este doar receptor, în timp ce memoria poate fi fie receptor fie emiţător. În timpul realizării

302 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 304 transferurilor de date, dispozitivele pot fi considerate ca master sau slave (vezi tabelul 5.12). Definiţii privind terminologia de magistrală I 2 C Tabelul Un dispozitiv este considerat master dacă iniţiază un transfer de date pe magistrală şi generează semnalul de ceas pentru a permite transferul. În acel moment, orice dispozitiv adresat e considerat slave. Întrucât magistrala I 2 C este de tip multimaster rezultă că pot fi conectate la aceasta mai mult de un dispozitiv capabil de a controla magistrala. Pentru a evita haosul care se poate instaura în urma unor astfel de evenimente se introduce o procedură de arbitrare. Aceasta se bazează pe conexiunea ŞI LOGIC (AND) a tuturor interfeţelor I 2 C aferente dispozitivelor conectate la magistrala I 2 C. Semnalul de ceas în timpul arbitrării este o combinaţie sincronizată a semnalelor de ceas generate de dispozitivele master folosind conexiunea ŞI LOGIC asupra liniei SCL. Fireşte, generarea semnalelor de ceas pe magistrala I 2 C este întotdeauna responsabilitatea dispozitivului master. Pentru transferarea datelor pe magistrală, fiecare din dispozitivele master generează propriul său semnal de ceas. Acest semnal poate fi alterat doar datorită unui dispozitiv slave lent, care întârzie semnalul activ de ceas sau de către un alt dispozitiv master când se realizează arbitrarea. Un dispozitiv master poate starta transferul doar dacă magistrala este liberă. Transferul datelor Pe durata unui transfer de date, apar două situaţii unice definite drept condiţii de START şi STOP. O tranziţie din stare HIGH în stare LOW a liniei de date (SDA), în timp ce semnalul de ceas (SCL) este în stare HIGH, indică o condiţie de START. O tranziţie din LOW în HIGH a liniei de date, în timp ce semnalul de ceas rămâne în stare HIGH, defineşte o condiţie de STOP. Cele două condiţii de START şi STOP sunt generate întotdeauna de

303 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 305 către dispozitivul master. Magistrala se consideră a fi ocupată după o condiţie de START şi liberă după o condiţie de STOP. Detecţia celor două condiţii de către dispozitivele conectate la magistrală este simplă dacă ele încorporează o interfaţă hardware necesară. Fiecare dată depusă pe linia de date (SDA) a magistralei I 2 C trebuie să aibă lungimea de 8 biţi. Numărul de octeţi transmişi per transfer este nelimitat. Fiecare octet trebuie să fie urmat de un bit de recunoaştere (Acknowledge). Datele sunt transferate cu cel mai semnificativ bit întâi. Dacă receptorul nu poate recepţiona complet octetul de date, deoarece se află în execuţia unui alt proces (ex: deservirea unei întreruperi), acesta reţine semnalul de ceas SCL în stare LOW forţând intrarea transmiţătorului în stare de aşteptare (wait). Transferul de date continuă de îndată ce receptorul este gata pentru a primi un alt octet de date şi eliberează semnalul de ceas. În unele cazuri, este permisă folosirea unor formate de date diferite faţă de formatul I 2 C bus (de exemplu, pentru dispozitive compatibile CBUS). Un mesaj care startează cu o adresă CBUS poate fi terminat prin generarea unei condiţii de STOP, chiar în timpul transmisiei unui octet, în acest caz, nefiind generat nici un bit de recunoaştere. Transferul de date trebuie să cuprindă obligatoriu bitul de recunoaştere. Bitul de Acknowledge este transmis de slave (vezi figura 5.23). Figura Dispozitivul Master emiţător adresează un Slave receptor cu o adresă pe 7 biţi Emiţătorul master eliberează linia de date (SDA), aflată în stare HIGH, pe durata respectivului impuls de tact. Totodată, receptorul trebuie să determine trecerea liniei de date în stare LOW. Fiecare bit de date este sincronizat cu un impuls de ceas (vezi figura 5.24).

304 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 306 Figura Transferul de date pe I 2 C De regulă, un receptor care a fost adresat este obligat să genereze bitul de recunoaştere (acknowledge) după fiecare octet recepţionat, excepţie făcând mesajele care încep cu o adresă CBUS. Când un slave receptor nu recunoaşte adresa de slave (de exemplu nu poate recepţiona deoarece execută o funcţie în timp real), linia de date trebuie lăsată în stare HIGH de către slave. Dispozitivul master poate genera atunci o condiţie de STOP care va întrerupe transferul. Dacă un slave receptor recunoaşte adresa, dar mai târziu în transfer nu mai poate recepţiona nici o dată, dispozitivul master trebuie să întrerupă din nou transferul. Acest lucru este indicat de către slave prin generarea unui bit de recunoaştere negat la finele primului octet ce urmează. Slave-ul lasă linia de date în stare HIGH iar dispozitivul master generează condiţia de STOP. Dacă un master receptor este implicat într-un transfer, el trebuie să semnaleze sfârşitul octeţilor de date emiţătorului slave, prin faptul de a nu genera un bit de acknowledge după ultimul octet trimis de slave. Slave-ul emiţător trebuie să elibereze linia de date pentru a permite dispozitivului master să genereze condiţia de STOP. Ca dispozitive master, de regulă, sunt utilizate microcontrollere. Presupunem următorul exemplu, de transfer de date între două microcontrollere conectate la magistrala I 2 C (vezi figura 5.25). Considerând transferul datelor în format cu 7 biţi de adresă se vor exemplifica două situaţii: una în care dispozitivul master este emiţător şi slave-ul receptor şi alta în care dispozitivul master este receptor iar slave-ul emiţător. După condiţia de start S, se transmite adresa unui slave pe 7 biţi. Aceasta este urmată de un bit de direcţie (R/ W ) (vezi figura 5.23). Dacă acesta este 0 indică o scriere de date (WRITE) iar succesiunea de mesaje este următoarea:

305 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 307 Figura Configuraţie de magistrală I 2 C folosind două microcontrollere 1. Presupunem că microcontrollerul A doreşte să trimită informaţie microcontrollerului B. Microcontrollerul A (master) apelează (adresează) microcontrollerul B (slave). Microcontrollerul A (emiţător) transmite data microcontrollerului B (receptor). Microcontrollerul A încheie transferul. Dacă bitul de direcţie este 1 el indică o cerere de date (READ), succesiunea de mesaje fiind (vezi figura 5.26): 2. Presupunem că microcontrollerul A doreşte să recepţioneze informaţie de la microcontrollerul B. Microcontrollerul A (master) se adresează microcontrollerului B (slave). Microcontrollerul A (master-receptor) primeşte data de al microcontrollerul B (slave-emiţător). Microcontrollerul A încheie transferul. Figura Dispozitivul Master-receptor citeşte datele trimise de Slave-ul - emiţător imediat după primul octet

306 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 308 Chiar şi în această situaţie, dispozitivul master va fi A, care va genera semnalul de ceas şi va încheia transferul. Transferul de date se încheie întotdeauna printr-o condiţie de stop P generată de către master. Totuşi, dacă un dispozitiv master doreşte să comunice pe magistrală, el poate genera o condiţie repetată de start Sr şi adresează un alt slave fără a genera întâi o condiţie de stop MAGISTRALA ACCESS.BUS Reprezintă magistrala de conectare a dispozitivelor accesorii la un calculator gazdă, un standard introdus de către compania Digital Equipment Corporation (actualmente înglobată în Compaq). Accesoriile sunt dispozitive periferice, de intrare / ieşire, având o viteză relativ redusă faţă de cea a calculatorului gazdă. Ca exemple de dispozitive accesorii amintim: tastatura, scanere, cititoare de cod de bare, cititoare de cartele magnetice (card), imprimanta, convertoare de semnal, aplicaţii de control în timp real etc. Topologia de conectare a dispozitivelor accesorii este de tip magistrală. Prin intermediul magistralei ACCESS pot fi conectate până la 125 de dispozitive periferice la un calculator gazdă. Lungimea cablului de conectare poate fi până la 8 m. Viteza maximă de transfer pe magistrală este de 80 Kbit/s. Magistrala ACCESS oferă avantaje atât utilizatorilor cât şi dezvoltatorilor de sisteme şi dispozitive periferice. Un calculator gazdă necesită doar un port hardware pentru conectarea la un număr de dispozitive. Trăsăturile comune în metodele de comunicare, pentru un număr mare de diverse tipuri de dispozitive, conduc la economii în dezvoltarea hardware şi software. Figura Magistrala ACCESS.bus o alternativă cost/performanţă interfeţei RS-232C

307 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 309 Nivelul hardware al magistralei ACCESS.bus La nivel hardware, magistrala ACCESS se bazează pe principiile magistralei seriale de interconectare a circuitelor integrate (I 2 C), prezentată succint anterior. Mediul fizic pentru magistrala ACCESS este compus dintrun cablu cu patru fire izolate între ele: semnalul de date (SDA), semnalul de ceas (SCL), alimentarea (+5V) şi masa (GND). Dispozitivele conectate la magistrală pot fi înlănţuite prin intermediul a doi conectori. Dispozitivele portabile pot avea un cablu de conectare la magistrala principală prin intermediul unui conector în T. Semnalele seriale de ceas şi date (SCL şi SDA) lucrează împreună pentru a defini informaţia transferată pe magistrală. Calculatorul gazdă alimentează prin intermediul liniei de +5V, asigurând un curent minim de 50 ma, dispozitivele periferice. Totodată acestea pot fi alimentate şi de o sursă externă. Nivelele ierarhice ale protocolului de magistrală ACCESS.bus Protocolul de comunicaţie ACCESS.bus e compus din trei nivele: protocolul I 2 C, protocolul de bază şi protocolul de aplicaţie. Figura Nivelele ierarhice ale protocolului de magistrală ACCESS.bus La nivelul cel mai de jos, apropiat de hardware, disciplina de bază a magistralei ACCESS e definită ca un subset al protocolului de magistrală I 2 C. Protocolul I 2 C defineşte o magistrală simetrică de tip multimaster, în care procesul de arbitrare între dispozitivele master se efectuează fără a pierde datele. Nivelul de protocol următor este protocolul de bază. Acest nivel e comun tuturor tipurilor de dispozitive conectate prin magistrala ACCESS şi

308 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 310 stabileşte natura asimetrică de interconectare între calculatorul gazdă şi un număr de dispozitive periferice. Calculatorul gazdă are un rol special ca manager al magistralei. Comunicaţia de date se face întotdeauna între calculator şi dispozitivele periferice, niciodată între două periferice. Dacă protocolul I 2 C asigură rol de conducător al unei tranzacţii pe magistrală fie emiţătorului fie receptorului, protocolul de comunicaţie ACCESS.bus asigură rol de master exclusiv emiţătorului, în timp ce rolul de slave e atribuit exclusiv receptorului. La momente diferite de timp, atât calculatorul gazdă cât şi dispozitivele periferice pot fi şi master / emiţător şi slave / receptor. Protocolul de bază al ACCESS.bus defineşte formatul mesajului împachetat, transferat prin magistrala ACCESS, care reprezintă o tranzacţie pe magistrala I 2 C, însoţită de o semantică suplimentară, incluzând sume de control. În plus, protocolul de bază defineşte un set de şapte controale şi tipuri de mesaje de stare care sunt folosite în procesul de configurare. Cele opt mesaje şi parametrii aferenţi care definesc protocolul de comunicaţie ACCESS.bus sunt: a. Mesaje de la calculatorul gazdă la dispozitivele periferice: 1. Reset (). 2. Identificarea cererii (). 3. Asignarea adresei (ID string, new addr) respectivului dispozitiv. 4. Cereri de capacitate (offset) (capabilities request) provenite de la un dispozitiv. b. Mesaje de la dispozitivele periferice la calculatorul gazdă: 1. Atenţionare (status). 2. Identificarea răspunsului (ID string). 3. Răspunsuri de capacitate (offset, data frag). 4. Eroare de interfaţă (). Două caracteristici unice ale procesului de configurare sunt autoadresarea şi conectarea rapidă la cald. Autoadresarea se referă la modul în care dispozitivelor le sunt asignate adrese de magistrală unice în procesul de configurare fără a fi nevoie pentru a seta jumperi sau comutatori ai dispozitivelor. Conectarea rapidă la cald se referă la abilitatea de ataşare sau deconectare a dispozitivelor, în timp ce sistemul funcţionează fără a fi nevoie de restartarea acestuia. Pe nivelul cel mai înalt privind protocolul de comunicaţie ACCESS.bus se află protocolul aplicaţie. Acesta defineşte semantica mesajelor specifice tipurilor funcţionale particulare de dispozitive. Tipuri diferite de dispozitive necesită protocoale de aplicaţie diferite. Acest tip de protocol a fost definit pentru trei clase de dispozitive: tastatură, dispozitive de transfer text şi dispozitive de localizare (locators).

309 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 311 Protocolul de tastatură defineşte mesajele standard generate în urma apăsării tastelor şi mesaje necesare controlului tastaturii. Protocolul încearcă să definească cel mai simplu set de funcţii din care poate fi construită interfaţa standard de tastatură. Protocolul aferent dispozitivelor localizatoare defineşte un set de mesaje standard generate în urma mişcării acestor dispozitive sau activării unor chei întrerupătoare (comutatoare) pentru dispozitivele de poziţionare. Dispozitive mai complexe pot fi modelate ca o combinaţie dintre dispozitive de bază sau pot asigura propriul lor driver. Protocolul de comunicaţie prin dispozitive cu transfer de text intenţionează să furnizeze un mod simplu de transmitere a datelor în format caracter sau binar, la şi de la dispozitive orientate fişier, cum sunt cititoare în cod de bare sau modem-uri. Modelul de fişier secvenţial în format caracter serveşte ca numitor comun pentru conectarea dispozitivelor interfaţă la RS-232C. Un avantaj major în proiectarea dispozitivelor este acela că ele pot împărţi software-ul specific unui dispozitiv, atât la nivel firmware (rezident în dispozitiv) cât şi la nivel software (rezident în driver), necesar sistemului de operare al calculatorului gazdă pentru a permite programelor de aplicaţie să acceseze respectivele dispozitive. Ca şi concluzie, toate cele trei nivele de protocol necesită inteligenţă la nivel de dispozitiv. Nivelele de protocol joase ale acestui firmware sunt comune mai multor dispozitive. Nivelele de protocol ridicate sunt specifice funcţie de dispozitiv sau aplicaţie. Kit-ul de dezvoltare ACCESS.bus ACCESS.bus este un standard industrial deschis ce asigură un mod simplu şi uniform de conectare a maxim 125 de dispozitive la un singur port al unui computer. Caracteristicile principale ar fi: rata de transfer a datelor biţi / s, arbitrare hardware, reconfigurare dinamică, suportă diverse drivere de dispozitiv. Caracteristicile kit-ului de dezvoltare software sunt: Satisface în întregime standardul ACCESS.bus. Pachetul hardware include: Controller-ul de placă ACCESS.bus 125I PC / AT. Un mouse ACCESS.bus. priză extensoare. Cabluri ACCESS.bus (2 ft picioare lungime şi 4 ft picioare lungime) Microcontroller Philips 87C751 (în mare parte compatibil 80C51). Pachetul software complet conţine: Microcod (MC) înscris pe placă aferent controller-ului principal.

310 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 312 Program manager, ce funcţionează ca un program TSR (terminate and stay resident) sub DOS. Program de monitorizare şi control al magistralei ACCESS.bus. Cod sursă pentru driver-ele software aferent atât calculatorului gazdă cât şi dispozitivelor periferice. Cod sursă pentru nivelul aplicaţie al protocolului ACCESS.bus. Figura Kit-ul de dezvoltare ACCESS.bus accesorii şi software complet Controller-ul de placă ACCESS.bus 125I PC / AT Se bazează pe microcontrollerul Philips 8xC654 cu interfaţă I 2 C. Interfaţa ACCESS.bus controlează o reţea de tip ACCESS.bus. Este realizată din conectori alimentaţi la +5V şi 0.75A. Dimensiunea reţelei ACCESS.bus este de maxim 125 de dispozitive. Distanţa fizică dintre dispozitive este maxim 25 ft (picioare, un picior ~ 0.3m). Interfaţa cu sistemul IBM PC / AT sau compatibil, se face folosind un mecanism PC / AT de intrare / ieşire programabil, pe 16 biţi. Adresele de I / O selectabile de utilizator sunt: De la 0x250 la 0x25F De la 0x260 la 0x26F De la 0x350 la 0x35F. Întreruperile selectabile de utilizator sunt: IRQ10, IRQ11 şi IRQ12. Pe placă se află un buffer de memorie de 8 ko SRAM (vezi figura 1.30).

311 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore 313 Figura Controller-ul de placă ACCESS.bus schema bloc Pachetul software aferent kit-ului de dezvoltare ACCESS.bus Microcodul (MC) înscris pe placă este un pachet de programe în timp real ce controlează operaţiilor diverselor dispozitive conectate la ACCESS.bus. Programul manager rulează ca un program rezident TSR (Terminate and Stay Resident) sub sistemul de operare DOS sau WINDOWS, comunică cu microcodul MC şi cu variate drivere de dispozitiv. El rutează mesajele de aplicaţie şi control între dispozitivele fizice şi driverele lor software. Programul monitor, este bazat pe meniuri, uşor accesibile utilizatorului, afişează mesajele selectate de utilizator şi permite acestuia să controleze dispozitivele specifice. La alimentarea plăcii este realizat un test complet de diagnosticare proprie (memorie, periferice aferente). Diagnosticarea se realizează sub controlul programului monitor. Protocolul CAN (reţea de control) CAN este un protocol de multiplexare al instalaţiilor electrice dezvoltat de firma Bosch pentru aplicaţii industriale automatizate, maşini şi utilaje, echipamene medicale, echipamente de control în construcţii. Protocolul este atractiv pentru utilizarea într-o varietate de aplicaţii deoarece reprezintă un instrument puternic de detecţie a erorilor. Poate fi utilizat cu succes în medii cu nivel de zgomot ridicat sau critic. CAN este foarte flexibil în termenii transmisiei de date şi schemei de conectare şi poate fi uşor adaptat la majoritatea aplicaţiilor. Compania Philips oferă o varietate de dispozitive care suportă protocolul CAN, cum ar fi: dispozitive stand-alone (de sine - stătătoare) dar şi microcontrollere cu interfaţă CAN integrată. Dintre acestea amintim: 82C200 controller stand alone, 82C150 (dispozitive periferice legate serial la CAN) şi 82C250 (controller de emisie recepţie legat la CAN). Exemple de microcontrollere care au integrate o interfaţă CAN sunt 8xC592 şi 8x598.

312 Arhitecturi cu executii multiple ale instructiunilor, vectoriale si multicore PLACA DE DEZVOLTARE DB 51 DB-51 este o placă de dezvoltare / proiectare a unui sistem de înaltă performanţă dedicat familiei de microcontollere Philips 80C51. DB-51 reprezintă un instrument flexibil, uşor de folosit care permite utilizatorului să construiască un prototip primar, să-l analizeze şi să-l depaneze, să facă schimbări asupra sa şi să continue depanarea. Îmbunătăţirea deciziilor de proiectare se face folosind DB-51 pentru a verifica şi testa avantajele câtorva microcontrollere diferite. De asemenea, placa de dezvoltare DB-51 reprezintă un instrument ideal de antrenare pentru familiarizarea utilizatorului cu proiectarea, folosind arhitectura 80C51. De remarcat că, DB-51 nu intenţionează totuşi să înlocuiască un sistem de emulare complet în proiectarea complexă cu microcontrollere. Caracteristici de bază Figura Placa de dezvoltare DB-51 Suportă majoritatea microcontrollerelor derivate ale familiei Philips 80C51 (8x31/51, 8x32/52, 8xC31/51, 8xC32/52, 8xC652, 8xC654, 8xC851, 8xC550, 8xC552, 8xC562, 8xC451, 8xC528 şi altele cu memorie externă adresabilă şi suport UART). Se conectează prin serial la un calculator IBM PC sau la alte calculatoare gazdă compatibile. Sistemul de memorie al DB-51 constă din 32 ko RAM. În acest spaţiu se încarcă şi modifică programele utilizator.

Metrici LPR interfatare cu Barix Barionet 50 -

Metrici LPR interfatare cu Barix Barionet 50 - Metrici LPR interfatare cu Barix Barionet 50 - Barionet 50 este un lan controller produs de Barix, care poate fi folosit in combinatie cu Metrici LPR, pentru a deschide bariera atunci cand un numar de

More information

Structura și Organizarea Calculatoarelor. Titular: BĂRBULESCU Lucian-Florentin

Structura și Organizarea Calculatoarelor. Titular: BĂRBULESCU Lucian-Florentin Structura și Organizarea Calculatoarelor Titular: BĂRBULESCU Lucian-Florentin Chapter 3 ADUNAREA ȘI SCĂDEREA NUMERELOR BINARE CU SEMN CONȚINUT Adunarea FXP în cod direct Sumator FXP în cod direct Scăderea

More information

Ierarhia memoriilor Tipuri de memorii Memorii semiconductoare Memoria cu unități multiple. Memoria cache Memoria virtuală

Ierarhia memoriilor Tipuri de memorii Memorii semiconductoare Memoria cu unități multiple. Memoria cache Memoria virtuală Ierarhia memoriilor Tipuri de memorii Memorii semiconductoare Memoria cu unități multiple Memoria cache Memoria virtuală 1 Memorii RAM: datele sunt identificate cu ajutorul unor adrese unice Memorii asociative:

More information

Versionare - GIT ALIN ZAMFIROIU

Versionare - GIT ALIN ZAMFIROIU Versionare - GIT ALIN ZAMFIROIU Controlul versiunilor - necesitate Caracterul colaborativ al proiectelor; Backup pentru codul scris Istoricul modificarilor Terminologie și concepte VCS Version Control

More information

9. Memoria. Procesorul are o memorie cu o arhitectură pe două niveluri pentru memoria de program și de date.

9. Memoria. Procesorul are o memorie cu o arhitectură pe două niveluri pentru memoria de program și de date. 9. Memoria Procesorul are o memorie cu o arhitectură pe două niveluri pentru memoria de program și de date. Primul nivel conține memorie de program cache (L1P) și memorie de date cache (L1D). Al doilea

More information

2. Setări configurare acces la o cameră web conectată într-un router ZTE H218N sau H298N

2. Setări configurare acces la o cameră web conectată într-un router ZTE H218N sau H298N Pentru a putea vizualiza imaginile unei camere web IP conectată într-un router ZTE H218N sau H298N, este necesară activarea serviciului Dinamic DNS oferit de RCS&RDS, precum și efectuarea unor setări pe

More information

Reflexia şi refracţia luminii. Aplicaţii. Valerica Baban

Reflexia şi refracţia luminii. Aplicaţii. Valerica Baban Reflexia şi refracţia luminii. Aplicaţii. Sumar 1. Indicele de refracţie al unui mediu 2. Reflexia şi refracţia luminii. Legi. 3. Reflexia totală 4. Oglinda plană 5. Reflexia şi refracţia luminii în natură

More information

CURS 9 SEMNALE LA INTERFAŢA UC CU EXTERIORUL CONTINUARE. Şef lucr. dr. ing. Dan FLOROIAN

CURS 9 SEMNALE LA INTERFAŢA UC CU EXTERIORUL CONTINUARE. Şef lucr. dr. ing. Dan FLOROIAN CURS 9 SEMNALE LA INTERFAŢA UC CU EXTERIORUL CONTINUARE Şef lucr. dr. ing. Dan FLOROIAN Magistrala de date Lărgimea magistralei de date este de obicei multiplu de octet (d = 8, 16, 32, 64...). Cele d linii

More information

Titlul lucrării propuse pentru participarea la concursul pe tema securității informatice

Titlul lucrării propuse pentru participarea la concursul pe tema securității informatice Titlul lucrării propuse pentru participarea la concursul pe tema securității informatice "Îmbunătăţirea proceselor şi activităţilor educaţionale în cadrul programelor de licenţă şi masterat în domeniul

More information

MS POWER POINT. s.l.dr.ing.ciprian-bogdan Chirila

MS POWER POINT. s.l.dr.ing.ciprian-bogdan Chirila MS POWER POINT s.l.dr.ing.ciprian-bogdan Chirila chirila@cs.upt.ro http://www.cs.upt.ro/~chirila Pornire PowerPoint Pentru accesarea programului PowerPoint se parcurg următorii paşi: Clic pe butonul de

More information

Semnale şi sisteme. Facultatea de Electronică şi Telecomunicaţii Departamentul de Comunicaţii (TC)

Semnale şi sisteme. Facultatea de Electronică şi Telecomunicaţii Departamentul de Comunicaţii (TC) Semnale şi sisteme Facultatea de Electronică şi Telecomunicaţii Departamentul de Comunicaţii (TC) http://shannon.etc.upt.ro/teaching/ssist/ 1 OBIECTIVELE CURSULUI Disciplina îşi propune să familiarizeze

More information

Auditul financiar la IMM-uri: de la limitare la oportunitate

Auditul financiar la IMM-uri: de la limitare la oportunitate Auditul financiar la IMM-uri: de la limitare la oportunitate 3 noiembrie 2017 Clemente Kiss KPMG in Romania Agenda Ce este un audit la un IMM? Comparatie: audit/revizuire/compilare Diferente: audit/revizuire/compilare

More information

MODELUL UNUI COMUTATOR STATIC DE SURSE DE ENERGIE ELECTRICĂ FĂRĂ ÎNTRERUPEREA ALIMENTĂRII SARCINII

MODELUL UNUI COMUTATOR STATIC DE SURSE DE ENERGIE ELECTRICĂ FĂRĂ ÎNTRERUPEREA ALIMENTĂRII SARCINII MODELUL UNUI COMUTATOR STATIC DE SURSE DE ENERGIE ELECTRICĂ FĂRĂ ÎNTRERUPEREA ALIMENTĂRII SARCINII Adrian Mugur SIMIONESCU MODEL OF A STATIC SWITCH FOR ELECTRICAL SOURCES WITHOUT INTERRUPTIONS IN LOAD

More information

Procesarea Imaginilor

Procesarea Imaginilor Procesarea Imaginilor Curs 11 Extragerea informańiei 3D prin stereoviziune Principiile Stereoviziunii Pentru observarea lumii reale avem nevoie de informańie 3D Într-o imagine avem doar două dimensiuni

More information

ARBORI AVL. (denumiti dupa Adelson-Velskii si Landis, 1962)

ARBORI AVL. (denumiti dupa Adelson-Velskii si Landis, 1962) ARBORI AVL (denumiti dupa Adelson-Velskii si Landis, 1962) Georgy Maximovich Adelson-Velsky (Russian: Гео ргий Макси мович Адельсо н- Ве льский; name is sometimes transliterated as Georgii Adelson-Velskii)

More information

Reţele Neuronale Artificiale în MATLAB

Reţele Neuronale Artificiale în MATLAB Reţele Neuronale Artificiale în MATLAB Programul MATLAB dispune de o colecţie de funcţii şi interfeţe grafice, destinate lucrului cu Reţele Neuronale Artificiale, grupate sub numele de Neural Network Toolbox.

More information

Tipuri și nivele de paralelism Clasificarea arhitecturilor paralele Arhitecturi vectoriale Arhitecturi SIMD Arhitecturi sistolice

Tipuri și nivele de paralelism Clasificarea arhitecturilor paralele Arhitecturi vectoriale Arhitecturi SIMD Arhitecturi sistolice Tipuri și nivele de paralelism Clasificarea arhitecturilor paralele Arhitecturi vectoriale Arhitecturi SIMD Arhitecturi sistolice Arhitecturi cu fire de execuție multiple 1 Arhitecturi cu memorie partajată

More information

Subiecte Clasa a VI-a

Subiecte Clasa a VI-a (40 de intrebari) Puteti folosi spatiile goale ca ciorna. Nu este de ajuns sa alegeti raspunsul corect pe brosura de subiecte, ele trebuie completate pe foaia de raspuns in dreptul numarului intrebarii

More information

Textul si imaginile din acest document sunt licentiate. Codul sursa din acest document este licentiat. Attribution-NonCommercial-NoDerivs CC BY-NC-ND

Textul si imaginile din acest document sunt licentiate. Codul sursa din acest document este licentiat. Attribution-NonCommercial-NoDerivs CC BY-NC-ND Textul si imaginile din acest document sunt licentiate Attribution-NonCommercial-NoDerivs CC BY-NC-ND Codul sursa din acest document este licentiat Public-Domain Esti liber sa distribui acest document

More information

3.2 Arhitectura setului de instrucţiuni ISA. Copyright Paul GASNER

3.2 Arhitectura setului de instrucţiuni ISA. Copyright Paul GASNER 3.2 Arhitectura setului de instrucţiuni ISA Copyright Paul GASNER Programarea CPU Programele scrise în limbaje de nivel înalt trebuie compilate pentru a obţine un program executabil Din punctul de vedere

More information

Propuneri pentru teme de licență

Propuneri pentru teme de licență Propuneri pentru teme de licență Departament Automatizări Eaton România Instalație de pompare cu rotire în funcție de timpul de funcționare Tablou electric cu 1 pompă pilot + 3 pompe mari, cu rotirea lor

More information

Posibilitati de realizare a transferurilor de date

Posibilitati de realizare a transferurilor de date Revista Informatica Economica, nr. 1 (17)/2001 1 Posibilitati de realizare a transferurilor de date Lect. Emanuela-Mariana CHICHEA Facultatea de Stiinte Economice, Universitatea din Craiova Transferul

More information

Dispozitive Electronice şi Electronică Analogică Suport curs 02 Metode de analiză a circuitelor electrice. Divizoare rezistive.

Dispozitive Electronice şi Electronică Analogică Suport curs 02 Metode de analiză a circuitelor electrice. Divizoare rezistive. . egimul de curent continuu de funcţionare al sistemelor electronice În acest regim de funcţionare, valorile mărimilor electrice ale sistemului electronic sunt constante în timp. Aşadar, funcţionarea sistemului

More information

GHID DE TERMENI MEDIA

GHID DE TERMENI MEDIA GHID DE TERMENI MEDIA Definitii si explicatii 1. Target Group si Universe Target Group - grupul demografic care a fost identificat ca fiind grupul cheie de consumatori ai unui brand. Toate activitatile

More information

Mecanismul de decontare a cererilor de plata

Mecanismul de decontare a cererilor de plata Mecanismul de decontare a cererilor de plata Autoritatea de Management pentru Programul Operaţional Sectorial Creşterea Competitivităţii Economice (POS CCE) Ministerul Fondurilor Europene - Iunie - iulie

More information

Documentaţie Tehnică

Documentaţie Tehnică Documentaţie Tehnică Verificare TVA API Ultima actualizare: 27 Aprilie 2018 www.verificaretva.ro 021-310.67.91 / 92 info@verificaretva.ro Cuprins 1. Cum funcţionează?... 3 2. Fluxul de date... 3 3. Metoda

More information

La fereastra de autentificare trebuie executati urmatorii pasi: 1. Introduceti urmatoarele date: Utilizator: - <numarul dvs de carnet> (ex: "9",

La fereastra de autentificare trebuie executati urmatorii pasi: 1. Introduceti urmatoarele date: Utilizator: - <numarul dvs de carnet> (ex: 9, La fereastra de autentificare trebuie executati urmatorii pasi: 1. Introduceti urmatoarele date: Utilizator: - (ex: "9", "125", 1573" - se va scrie fara ghilimele) Parola: -

More information

SIMULAREA SISTEMULUI IERARHIC DE MEMORIE ÎN ARHITECTURI DE TIP MULTIPROCESOR CU MEMORIE PARTAJATĂ

SIMULAREA SISTEMULUI IERARHIC DE MEMORIE ÎN ARHITECTURI DE TIP MULTIPROCESOR CU MEMORIE PARTAJATĂ SIMULAREA SISTEMULUI IERARHIC DE MEMORIE ÎN ARHITECTURI DE TIP MULTIPROCESOR CU MEMORIE PARTAJATĂ 1.1. INTRODUCERE. SCOPUL LUCRĂRII Limitările majore în cresterea performanței sistemelor monoprocesor (așa

More information

Arbori. Figura 1. struct ANOD { int val; ANOD* st; ANOD* dr; }; #include <stdio.h> #include <conio.h> struct ANOD { int val; ANOD* st; ANOD* dr; }

Arbori. Figura 1. struct ANOD { int val; ANOD* st; ANOD* dr; }; #include <stdio.h> #include <conio.h> struct ANOD { int val; ANOD* st; ANOD* dr; } Arbori Arborii, ca şi listele, sunt structuri dinamice. Elementele structurale ale unui arbore sunt noduri şi arce orientate care unesc nodurile. Deci, în fond, un arbore este un graf orientat degenerat.

More information

Multicore Multiprocesoare Cluster-e

Multicore Multiprocesoare Cluster-e Multicore Multiprocesoare Cluster-e O mare perioadă de timp, creearea de calculatoare puternice conectarea mai multor calculatoare de putere mică. Trebuie creat software care să știe să lucreze cu un număr

More information

Lucrarea de laborator nr. 4

Lucrarea de laborator nr. 4 Metode merice - Lucrarea de laborator 4 Lucrarea de laborator nr. 4 I. Scopul lucrării Elemente de programare în MAPLE II. III. Conţinutul lucrării 1. Atribuirea. Decizia. Structuri repetitive. 2. Proceduri

More information

.. REGISTRE Registrele sunt circuite logice secvenţiale care primesc, stochează şi transferă informaţii sub formă binară. Un registru este format din mai multe celule bistabile de tip RS, JK sau D şi permite

More information

SISTEMUL DE INTRARE - IEŞIRE

SISTEMUL DE INTRARE - IEŞIRE CAPITOLUL 7 SISTEMUL DE INTRARE - IEŞIRE Conţinut: 7.1. Circuite de interfaţă 7.2. Organizarea ierarhică a magistralelor 7.3. Transferuri asincrone de date 7.3.1. Transmisie asincronă cu un singur semnal

More information

ARHITECTURA CALCULATOARELOR LABORATOR PROGRAMĂ ANALITICĂ OBIECTIVE CURS. Obiective educaţionale: Profesor Mihai ROMANCA

ARHITECTURA CALCULATOARELOR LABORATOR PROGRAMĂ ANALITICĂ OBIECTIVE CURS. Obiective educaţionale: Profesor Mihai ROMANCA ARHITECTURA CALCULATOARELOR Profesor Mihai ROMANCA Departamentul Automatică, Electronică şi Calculatoare email: romanca@unitbv.ro Web page curs: http://vega.unitbv.ro/~romanca/calc OBIECTIVE CURS Introducere

More information

Ghid identificare versiune AWP, instalare AWP şi verificare importare certificat în Store-ul de Windows

Ghid identificare versiune AWP, instalare AWP şi verificare importare certificat în Store-ul de Windows Ghid identificare versiune AWP, instalare AWP 4.5.4 şi verificare importare certificat în Store-ul de Windows Data: 28.11.14 Versiune: V1.1 Nume fişiser: Ghid identificare versiune AWP, instalare AWP 4-5-4

More information

Programare în limbaj de asamblare 16. Formatul instrucţiunilor (codificare, moduri de adresare).

Programare în limbaj de asamblare 16. Formatul instrucţiunilor (codificare, moduri de adresare). Platformă de e-learning și curriculă e-content pentru învățământul superior tehnic Programare în limbaj de asamblare 16. Formatul instrucţiunilor (codificare, moduri de adresare). Formatul instrucţiunilor

More information

Achiziţia de date în sistemele SCADA

Achiziţia de date în sistemele SCADA Cuprins Achiziţia de date în sistemele SCADA Achiziţia de date în sistemele SCADA...1 Obiective...1 Organizarea sarcinilor de lucru...1 1. Elemente introductive despre convertoarele analog numerice...2

More information

COMUNICAȚII INFORMATIZARE

COMUNICAȚII INFORMATIZARE COMUNICAȚII INFORMATIZARE 120 Migrare servicii telefonie la Vodafone S-a asigurat suportul tehnic și s-a colaborat cu echipele Vodafone la portarea numerelor UPT și migrarea infrastructuri: 1200 linii

More information

Tema 1 - Transferuri de date DMA intr-o arhitectura de tip Cell

Tema 1 - Transferuri de date DMA intr-o arhitectura de tip Cell Tema 1 - Transferuri de date DMA intr-o arhitectura de tip Cell Termen de trimitere a temei: Luni, 31 martie 2008, ora 23:55 1. Specificatii functionale O arhitectura de tip Cell consta din urmatoarele

More information

Laborator 07. Procesorul MIPS versiune pe 16 biți, cu un ciclu de ceas pe instrucțiune

Laborator 07. Procesorul MIPS versiune pe 16 biți, cu un ciclu de ceas pe instrucțiune Laborator 07 Procesorul MIPS versiune pe 16 biți, cu un ciclu de ceas pe instrucțiune Unitatea de Instruction Execute EX / Unitatea de Memorie MEM / Unitatea Write-Back WB 0. Resurse minimale necesare!

More information

Memorii în Sisteme Embedded. Tipuri de memorii. Arhitectura memoriilor.

Memorii în Sisteme Embedded. Tipuri de memorii. Arhitectura memoriilor. Memorii în Sisteme Embedded Tipuri de memorii. Arhitectura memoriilor. De ce avem nevoie de memorii în sisteme embedded? Stocarea datelor Temporar Pe termen lung Comunicare între componentele programelor

More information

SIMULATORUL PCSPIM-CACHE

SIMULATORUL PCSPIM-CACHE SIMULATORUL PCSPIM-CACHE 1.1. SCOPUL LUCRĂRII Memoriile cache reprezintă un mecanism omniprezent în microprocesoarele curente, dedicat mascării latenţei ridicate a memoriei principale. Datorită importanţei

More information

Pentru fiecare dintre următorii itemi alegeți litera corespunzătoare răspunsului corect.

Pentru fiecare dintre următorii itemi alegeți litera corespunzătoare răspunsului corect. Pentru fiecare dintre următorii itemi alegeți litera corespunzătoare răspunsului corect. 1. Care dintre următoarele exemple reprezintă un sistem de operare? a. Windows b. Word c. Lotus d. PowerPoint 2.

More information

ISBN-13:

ISBN-13: Regresii liniare 2.Liniarizarea expresiilor neliniare (Steven C. Chapra, Applied Numerical Methods with MATLAB for Engineers and Scientists, 3rd ed, ISBN-13:978-0-07-340110-2 ) Există cazuri în care aproximarea

More information

Olimpiad«Estonia, 2003

Olimpiad«Estonia, 2003 Problema s«pt«m nii 128 a) Dintr-o tabl«p«trat«(2n + 1) (2n + 1) se ndep«rteaz«p«tr«telul din centru. Pentru ce valori ale lui n se poate pava suprafata r«mas«cu dale L precum cele din figura de mai jos?

More information

Modalitǎţi de clasificare a datelor cantitative

Modalitǎţi de clasificare a datelor cantitative Modalitǎţi de clasificare a datelor cantitative Modul de stabilire a claselor determinarea pragurilor minime şi maxime ale fiecǎrei clase - determinǎ modul în care sunt atribuite valorile fiecǎrei clase

More information

2. PORTUL PARALEL ÎMBUNĂTĂŢIT

2. PORTUL PARALEL ÎMBUNĂTĂŢIT 2. PORTUL PARALEL ÎMBUNĂTĂŢIT 2.1. Scopul lucrării Lucrarea prezintă portul paralel îmbunătăţit al calculatoarelor IBM PC, pe baza standardului IEEE 1284. Sunt prezentate modurile de transfer specificate

More information

SISTEME DE CALCUL. LIMBAJ DE ASAMBLARE. SIMULATORUL PCSPIM UAL DPE. Fig.1. Structura unui sistem de calcul

SISTEME DE CALCUL. LIMBAJ DE ASAMBLARE. SIMULATORUL PCSPIM UAL DPE. Fig.1. Structura unui sistem de calcul SISTEME DE CALCUL. LIMBAJ DE ASAMBLARE. SIMULATORUL PCSPIM I. Sisteme de calcul 1. Arhitectura generală a unui sistem de calcul DPI UCC MEM Canale I/E DPI/E, MEM externe UAL DPE UCP UC Fig.1. Structura

More information

X-Fit S Manual de utilizare

X-Fit S Manual de utilizare X-Fit S Manual de utilizare Compatibilitate Acest produs este compatibil doar cu dispozitivele ce au următoarele specificații: ios: Versiune 7.0 sau mai nouă, Bluetooth 4.0 Android: Versiune 4.3 sau mai

More information

Software Process and Life Cycle

Software Process and Life Cycle Software Process and Life Cycle Drd.ing. Flori Naghiu Murphy s Law: Left to themselves, things tend to go from bad to worse. Principiile de dezvoltare software Principiul Calitatii : asigurarea gasirii

More information

SISTEME DE CALCUL. LIMBAJ DE ASAMBLARE. SIMULATORUL QTSPIM UAL DPE. Fig.1. Structura unui sistem de calcul

SISTEME DE CALCUL. LIMBAJ DE ASAMBLARE. SIMULATORUL QTSPIM UAL DPE. Fig.1. Structura unui sistem de calcul SISTEME DE CALCUL. LIMBAJ DE ASAMBLARE. SIMULATORUL QTSPIM I. Sisteme de calcul 1. Arhitectura generală a unui sistem de calcul DPI UCC MEM Canale I/E DPI/E, MEM externe UAL DPE UCP UC Fig.1. Structura

More information

Update firmware aparat foto

Update firmware aparat foto Update firmware aparat foto Mulţumim că aţi ales un produs Nikon. Acest ghid descrie cum să efectuaţi acest update de firmware. Dacă nu aveţi încredere că puteţi realiza acest update cu succes, acesta

More information

Lucrarea Nr.1. Sisteme de operare. Generalitati

Lucrarea Nr.1. Sisteme de operare. Generalitati Lucrarea Nr.1 Sisteme de operare. Generalitati Scopul lucrarii Lucrarea îsi propune familiarizarea studentilor cu sistemele de operare disponibile în laborator, respectiv acele sisteme de operare cu ajutorul

More information

Aspecte controversate în Procedura Insolvenţei şi posibile soluţii

Aspecte controversate în Procedura Insolvenţei şi posibile soluţii www.pwc.com/ro Aspecte controversate în Procedura Insolvenţei şi posibile soluţii 1 Perioada de observaţie - Vânzarea de stocuri aduse în garanţie, în cursul normal al activității - Tratamentul leasingului

More information

Managementul Proiectelor Software Metode de dezvoltare

Managementul Proiectelor Software Metode de dezvoltare Platformă de e-learning și curriculă e-content pentru învățământul superior tehnic Managementul Proiectelor Software Metode de dezvoltare 2 Metode structurate (inclusiv metodele OO) O mulțime de pași și

More information

REVISTA NAŢIONALĂ DE INFORMATICĂ APLICATĂ INFO-PRACTIC

REVISTA NAŢIONALĂ DE INFORMATICĂ APLICATĂ INFO-PRACTIC REVISTA NAŢIONALĂ DE INFORMATICĂ APLICATĂ INFO-PRACTIC Anul II Nr. 7 aprilie 2013 ISSN 2285 6560 Referent ştiinţific Lector univ. dr. Claudiu Ionuţ Popîrlan Facultatea de Ştiinţe Exacte Universitatea din

More information

Evoluția pieței de capital din România. 09 iunie 2018

Evoluția pieței de capital din România. 09 iunie 2018 Evoluția pieței de capital din România 09 iunie 2018 Realizări recente Realizări recente IPO-uri realizate în 2017 și 2018 IPO în valoare de EUR 312.2 mn IPO pe Piața Principală, derulat în perioada 24

More information

CAPITOLUL 1 SISTEME DE CALCUL

CAPITOLUL 1 SISTEME DE CALCUL CAPITOLUL 1 SISTEME DE CALCUL 1.1. Introducere Din cele mai vechi timpuri oamenii au căutat să simplifice anumite activităţi, cum este şi aceea de numărare. Astfel a luat naştere abacul, care poate fi

More information

3. CLOUD COMPUTING Sisteme de calcul distribuite

3. CLOUD COMPUTING Sisteme de calcul distribuite 3. CLOUD COMPUTING Cloud Computing (CC) calcul în nori, în traducere mot a mot, sau, mai corect, calcul în Internet este un concept aflat în directă legătură cu transformările către se produc în domeniu

More information

Curs 1 17 Februarie Adrian Iftene

Curs 1 17 Februarie Adrian Iftene Curs 1 17 Februarie 2011 Adrian Iftene adiftene@info.uaic.ro 1 Limbajele calculatorului Compilate Interpretate Scripting P-cod Orientate pe aspect Orientate spre date 2 Cum lucrează? Orice program trebuie

More information

Solutii avansate pentru testarea si diagnoza masinilor industriale.

Solutii avansate pentru testarea si diagnoza masinilor industriale. Solutii avansate pentru testarea si diagnoza masinilor industriale 15 ani de activitate in domeniul procesarii numerice a semnalelor Solutii de inalta acuratete pentru analiza sunetelor, vibratiilor si

More information

7. INTERFAȚA ATA Prezentare generală a interfeței ATA. Sisteme de intrare/ieșire și echipamente periferice

7. INTERFAȚA ATA Prezentare generală a interfeței ATA. Sisteme de intrare/ieșire și echipamente periferice Sisteme de intrare/ieșire și echipamente periferice 1 7. INTERFAȚA ATA Această lucrare de laborator prezintă mai multe variante ale interfeței ATA pentru unitățile de discuri și pune în evidență îmbunătățirile

More information

Anexa nr. 1 la Hotărârea nr. 245 din Standarde moldovenești adoptate

Anexa nr. 1 la Hotărârea nr. 245 din Standarde moldovenești adoptate # Indicativul standardului moldovenesc 1 SM EN 300 224 română Serviciu mobil terestru. Echipamente radio pentru utilizarea într-un serviciu de paging în domeniul de frecvenţă de la 25 MHz până la 470 MHz.

More information

Class D Power Amplifiers

Class D Power Amplifiers Class D Power Amplifiers A Class D amplifier is a switching amplifier based on pulse-width modulation (PWM) techniques Purpose: high efficiency, 80% - 95%. The reduction of the power dissipated by the

More information

Mihai ROMANCA. Microprocesoare şi microcontrolere

Mihai ROMANCA. Microprocesoare şi microcontrolere Mihai ROMANCA Microprocesoare şi microcontrolere Universitatea Transilvania din Braşov 2015 Cuprins 1 CUPRINS Cuprins... 1 Cuvânt înainte... 3 1. INTRODUCERE ÎN ARHITECTURA MICROPROCESOARELOR... 5 1.1.

More information

2. Setări configurare acces la o cameră web conectată într-un echipament HG8121H cu funcție activă de router

2. Setări configurare acces la o cameră web conectată într-un echipament HG8121H cu funcție activă de router Pentru a putea vizualiza imaginile unei camere web IP conectată într-un echipament Huawei HG8121H, este necesară activarea serviciului Dinamic DNS oferit de RCS&RDS, precum și efectuarea unor setări pe

More information

SISTEME CU CIRCUITE INTEGRATE DIGITALE (EA II) ELECTRONICĂ DIGITALĂ (CAL I) Prof.univ.dr.ing. Oniga Ștefan

SISTEME CU CIRCUITE INTEGRATE DIGITALE (EA II) ELECTRONICĂ DIGITALĂ (CAL I) Prof.univ.dr.ing. Oniga Ștefan SISTEME CU CIRCUITE INTEGRATE DIGITALE (EA II) ELECTRONICĂ DIGITALĂ (CAL I) Prof.univ.dr.ing. Oniga Ștefan Convertoare numeric analogice şi analog numerice Semnalele din lumea reală, preponderent analogice,

More information

Contact Center, un serviciu cri/c!

Contact Center, un serviciu cri/c! Contact Center, un serviciu cri/c! CASE STUDY: Apa Nova Cisco Unified Contact Center Enterprise Agenda Prezentării Ø Perspec/va de business Ø Despre noi Ø Cerinţe de business Ø Opţiunea Apa Nova Ø Beneficii

More information

INFORMAȚII DESPRE PRODUS. FLEXIMARK Stainless steel FCC. Informații Included in FLEXIMARK sample bag (article no. M )

INFORMAȚII DESPRE PRODUS. FLEXIMARK Stainless steel FCC. Informații Included in FLEXIMARK sample bag (article no. M ) FLEXIMARK FCC din oțel inoxidabil este un sistem de marcare personalizată în relief pentru cabluri și componente, pentru medii dure, fiind rezistent la acizi și la coroziune. Informații Included in FLEXIMARK

More information

Lucian N. VINTAN. Arhitecturi de procesoare cu paralelism la nivelul instructiunilor ISBN

Lucian N. VINTAN. Arhitecturi de procesoare cu paralelism la nivelul instructiunilor ISBN Lucian N. VINTAN Arhitecturi de procesoare cu paralelism la nivelul instructiunilor ISBN 973-27-0734-8 Editura Academiei Române Bucuresti, 2000 CUPRINS 1. INTRODUCERE...10 2. PROCESOARE PIPELINE SCALARE

More information

Mods euro truck simulator 2 harta romaniei by elyxir. Mods euro truck simulator 2 harta romaniei by elyxir.zip

Mods euro truck simulator 2 harta romaniei by elyxir. Mods euro truck simulator 2 harta romaniei by elyxir.zip Mods euro truck simulator 2 harta romaniei by elyxir Mods euro truck simulator 2 harta romaniei by elyxir.zip 26/07/2015 Download mods euro truck simulator 2 harta Harta Romaniei pentru Euro Truck Simulator

More information

Candlesticks. 14 Martie Lector : Alexandru Preda, CFTe

Candlesticks. 14 Martie Lector : Alexandru Preda, CFTe Candlesticks 14 Martie 2013 Lector : Alexandru Preda, CFTe Istorie Munehisa Homma - (1724-1803) Ojima Rice Market in Osaka 1710 devine si piata futures Parintele candlesticks Samurai In 1755 a scris The

More information

Laborator 1. Programare declarativă. Programare logică. Prolog. SWI-Prolog

Laborator 1. Programare declarativă. Programare logică. Prolog. SWI-Prolog Laborator 1 Programare declarativă O paradigmă de programare în care controlul fluxului de execuție este lăsat la latitudinea implementării limbajului, spre deosebire de programarea imperativă în care

More information

Calculatoare Numerice II Interfaţarea unui dispozitiv de teleghidare radio cu portul paralel (MGSH Machine Guidance SHell) -proiect-

Calculatoare Numerice II Interfaţarea unui dispozitiv de teleghidare radio cu portul paralel (MGSH Machine Guidance SHell) -proiect- Universitatea Politehnica Bucureşti Facultatea de Automaticăşi Calculatoare Calculatoare Numerice II Interfaţarea unui dispozitiv de teleghidare radio cu portul paralel (MGSH Machine Guidance SHell) -proiect-

More information

6. Bucle. 6.1 Instrucţiunea while

6. Bucle. 6.1 Instrucţiunea while 6. Bucle În capitolul trecut am văzut cum putem selecta diferite instrucţiuni pentru execuţie folosind instrucţiunea if. O buclă este o structură de control care provoacă executarea unei instrucţiuni sau

More information

Metoda BACKTRACKING. prof. Jiduc Gabriel

Metoda BACKTRACKING. prof. Jiduc Gabriel Metoda BACKTRACKING prof. Jiduc Gabriel Un algoritm backtracking este un algoritm de căutare sistematică și exhausivă a tuturor soluțiilor posibile, dintre care se poate alege apoi soluția optimă. Problemele

More information

CAIETUL DE SARCINI Organizare evenimente. VS/2014/0442 Euro network supporting innovation for green jobs GREENET

CAIETUL DE SARCINI Organizare evenimente. VS/2014/0442 Euro network supporting innovation for green jobs GREENET CAIETUL DE SARCINI Organizare evenimente VS/2014/0442 Euro network supporting innovation for green jobs GREENET Str. Dem. I. Dobrescu, nr. 2-4, Sector 1, CAIET DE SARCINI Obiectul licitaţiei: Kick off,

More information

ANTICOLLISION ALGORITHM FOR V2V AUTONOMUOS AGRICULTURAL MACHINES ALGORITM ANTICOLIZIUNE PENTRU MASINI AGRICOLE AUTONOME TIP V2V (VEHICLE-TO-VEHICLE)

ANTICOLLISION ALGORITHM FOR V2V AUTONOMUOS AGRICULTURAL MACHINES ALGORITM ANTICOLIZIUNE PENTRU MASINI AGRICOLE AUTONOME TIP V2V (VEHICLE-TO-VEHICLE) ANTICOLLISION ALGORITHM FOR VV AUTONOMUOS AGRICULTURAL MACHINES ALGORITM ANTICOLIZIUNE PENTRU MASINI AGRICOLE AUTONOME TIP VV (VEHICLE-TO-VEHICLE) 457 Florin MARIAŞIU*, T. EAC* *The Technical University

More information

Arhitectura sistemelor de calcul paralel

Arhitectura sistemelor de calcul paralel Arhitectura sistemelor de calcul paralel CURS 1 17.02.2014 Exemple de procese paralele si aplicatii Lumea reala un laborator gigactic de procese paralele Aplicatii Rezolvarea numerica a unor probleme care

More information

D în această ordine a.î. AB 4 cm, AC 10 cm, BD 15cm

D în această ordine a.î. AB 4 cm, AC 10 cm, BD 15cm Preparatory Problems 1Se dau punctele coliniare A, B, C, D în această ordine aî AB 4 cm, AC cm, BD 15cm a) calculați lungimile segmentelor BC, CD, AD b) determinați distanța dintre mijloacele segmentelor

More information

Principalele blocuri interne ale microprocesorului 8085 sunt prezentate în Figura 1: Comandă întreruperi și I/O seriale. Bistabile condiții (5 biți)

Principalele blocuri interne ale microprocesorului 8085 sunt prezentate în Figura 1: Comandă întreruperi și I/O seriale. Bistabile condiții (5 biți) L6. ARHITECTURA MICROPROCESORULUI 8085. MODUL DE EXECUȚIE A INSTRUCȚIUNILOR. APLICAȚII DE VIZUALIZARE/EDITARE A CONȚINUTULUI UNOR REGISTRE ȘI LOCAȚII DE MEMORIE PE PLACA DE DEZVOLTARE. 1. Obiective Prin

More information

Transmiterea datelor prin reteaua electrica

Transmiterea datelor prin reteaua electrica PLC - Power Line Communications dr. ing. Eugen COCA Universitatea Stefan cel Mare din Suceava Facultatea de Inginerie Electrica PLC - Power Line Communications dr. ing. Eugen COCA Universitatea Stefan

More information

Evoluţii în sistemele de măsurat

Evoluţii în sistemele de măsurat Evoluţii în sistemele de măsurat Schema generală a unui sistem de măsurat I Sistem observat Sensor Procesor de informaţie Actuator Executant Procesorul de informaţie(1) În 1904 John Ambrose Fleming, inventează

More information

5.3 OSCILATOARE SINUSOIDALE

5.3 OSCILATOARE SINUSOIDALE 5.3 OSCILATOARE SINUSOIDALE 5.3.1. GENERALITĂŢI Oscilatoarele sunt circuite electronice care generează la ieşire o formă de undă repetitivă, cu frecvenţă proprie, fără a fi necesar un semnal de intrare

More information

9. INTERFAŢA SCSI Scopul lucrării Consideraţii teoretice Prezentarea interfeţei SCSI

9. INTERFAŢA SCSI Scopul lucrării Consideraţii teoretice Prezentarea interfeţei SCSI 9. INTERFAŢA SCSI 9.1. Scopul lucrării Lucrarea prezintă diferitele tipuri de interfeţe SCSI, standardele SCSI care au fost elaborate sau sunt în curs de elaborare, semnalele magistralei SCSI şi funcţionarea

More information

INSTRUMENTE DE MARKETING ÎN PRACTICĂ:

INSTRUMENTE DE MARKETING ÎN PRACTICĂ: INSTRUMENTE DE MARKETING ÎN PRACTICĂ: Marketing prin Google CUM VĂ AJUTĂ ACEST CURS? Este un curs util tuturor celor implicați în coordonarea sau dezvoltarea de campanii de marketingși comunicare online.

More information

Managementul referinţelor cu

Managementul referinţelor cu TUTORIALE DE CULTURA INFORMAŢIEI Citarea surselor de informare cu instrumente software Managementul referinţelor cu Bibliotecar Lenuţa Ursachi PE SCURT Este gratuit Poţi adăuga fişiere PDF Poţi organiza,

More information

PROIECTAREA ALGORITMILOR

PROIECTAREA ALGORITMILOR Universitatea Constantin Brâncuşi Târgu-Jiu Facultatea de Inginerie Departamentul de Automatică, Energie şi Mediu 3 PROIECTAREA ALGORITMILOR Lect. univ. dr. Adrian Runceanu 1 Curs 3 Alocarea dinamică de

More information

MANAGEMENTUL CALITĂȚII - MC. Proiect 5 Procedura documentată pentru procesul ales

MANAGEMENTUL CALITĂȚII - MC. Proiect 5 Procedura documentată pentru procesul ales MANAGEMENTUL CALITĂȚII - MC Proiect 5 Procedura documentată pentru procesul ales CUPRINS Procedura documentată Generalități Exemple de proceduri documentate Alegerea procesului pentru realizarea procedurii

More information

UNITATEA CENTRALĂ DE PRELUCRARE CPU12

UNITATEA CENTRALĂ DE PRELUCRARE CPU12 CAPITOLUL 2 UNITATEA CENTRALĂ DE PRELUCRARE CPU12 2.1. INTRODUCERE Unitatea centrală de prelucrare CPU12 este componentă a unui microcontroler din familia HCS12X. Principalele componente ale microcontrolerului

More information

LIDER ÎN AMBALAJE EXPERT ÎN SISTEMUL BRAILLE

LIDER ÎN AMBALAJE EXPERT ÎN SISTEMUL BRAILLE LIDER ÎN AMBALAJE EXPERT ÎN SISTEMUL BRAILLE BOBST EXPERTFOLD 80 ACCUBRAILLE GT Utilajul ACCUBRAILLE GT Bobst Expertfold 80 Aplicarea codului Braille pe cutii a devenit mai rapidă, ușoară și mai eficientă

More information

R O M Â N I A CURTEA CONSTITUŢIONALĂ

R O M Â N I A CURTEA CONSTITUŢIONALĂ R O M Â N I A CURTEA CONSTITUŢIONALĂ Palatul Parlamentului Calea 13 Septembrie nr. 2, Intrarea B1, Sectorul 5, 050725 Bucureşti, România Telefon: (+40-21) 312 34 84; 335 62 09 Fax: (+40-21) 312 43 59;

More information

SISTEME INTELIGENTE DE SUPORT DECIZIONAL. Ș.l.dr.ing. Laura-Nicoleta IVANCIU. Curs 7 Sisteme inteligente de suport decizional bazate pe RNA

SISTEME INTELIGENTE DE SUPORT DECIZIONAL. Ș.l.dr.ing. Laura-Nicoleta IVANCIU. Curs 7 Sisteme inteligente de suport decizional bazate pe RNA SISTEME INTELIGENTE DE SUPORT DECIZIONAL Ș.l.dr.ing. Laura-Nicoleta IVANCIU Curs 7 Sisteme inteligente de suport decizional bazate pe RNA Cuprins RNA pentru aproximare de funcții Clasificatori cu RNA Studii

More information

Arhitectura calculatoarelor Lucrarea de laborator Nr. 6 1 PORTUL PARALEL

Arhitectura calculatoarelor Lucrarea de laborator Nr. 6 1 PORTUL PARALEL Arhitectura calculatoarelor Lucrarea de laborator Nr. 6 1 PORTUL PARALEL 1. Scopul lucrării Lucrarea prezintă portul paralel standard şi portul paralel îmbunătăţit al calculatoarelor compatibile IBM PC.

More information

Lucrarea 10. Echipamente pentru introducerea datelor

Lucrarea 10. Echipamente pentru introducerea datelor Lucrarea 10 Echipamente pentru introducerea datelor I. TASTATURA În ciuda tuturor dispozitivelor moderne de introducere a datelor, cum ar fi mouse-ul, scaner-ul şi sistemele de comandă prin voce, tastatura

More information

Grafuri bipartite. Lecție de probă, informatică clasa a XI-a. Mihai Bărbulescu Facultatea de Automatică și Calculatoare, UPB

Grafuri bipartite. Lecție de probă, informatică clasa a XI-a. Mihai Bărbulescu Facultatea de Automatică și Calculatoare, UPB Grafuri bipartite Lecție de probă, informatică clasa a XI-a Mihai Bărbulescu b12mihai@gmail.com Facultatea de Automatică și Calculatoare, UPB Colegiul Național de Informatică Tudor Vianu București 27 februarie

More information

Rem Ahsap is one of the prominent companies of the market with integrated plants in Turkey, Algeria and Romania and sales to 26 countries worldwide.

Rem Ahsap is one of the prominent companies of the market with integrated plants in Turkey, Algeria and Romania and sales to 26 countries worldwide. Ȋncepându-şi activitatea ȋn 2004, Rem Ahsap este una dintre companiile principale ale sectorului fabricǎrii de uşi având o viziune inovativǎ şi extinsǎ, deschisǎ la tot ce ȋnseamnǎ dezvoltare. Trei uzine

More information

Universitatea Politehnica București. Facultatea de Electronică, Telecomunicații și Tehnologia Informației

Universitatea Politehnica București. Facultatea de Electronică, Telecomunicații și Tehnologia Informației Universitatea Politehnica București Facultatea de Electronică, Telecomunicații și Tehnologia Informației Proiect Sisteme de Operare Avansate Mașini Virtuale Procesul de virtualizare și accesul la resurse

More information

LINEAR VOLTAGE-TO-CURRENT CONVERTER WITH SMALL AREA

LINEAR VOLTAGE-TO-CURRENT CONVERTER WITH SMALL AREA BULETINUL INSTITUTULUI POLITEHNIC DIN IAŞI Publicat de Universitatea Tehnică Gheorghe Asachi din Iaşi Tomul LXI (LXV), Fasc. 1, 2015 Secţia ELECTROTEHNICĂ. ENERGETICĂ. ELECTRONICĂ LINEAR VOLTAGE-TO-CURRENT

More information

Implementarea paralelismului la nivel de instructiune în microprocesoarele superscalare

Implementarea paralelismului la nivel de instructiune în microprocesoarele superscalare Revista Informatica Economica, nr. 8/1998 67 Implementarea paralelismului la nivel de instructiune în microprocesoarele superscalare Prof.dr.ing. Gheorghe DODESCU Catedra de Informatica Economica, A.S.E.

More information