Documente noi - cercetari, esee, comentariu, compunere, document
Documente categorii

Microprocesoare pe 32 biti

Microprocesoare pe 32 biti

Aparitia microprocesorului 80386 a reprezentat un salt major in familia Intel. Pe langa cresterea dimensiunii operanzilor de la 16 la 32 biti, au fost introduse o serie de noi caracteristici care au imbunatatit substantial performantele si functionalitatea. Linia inovativa a fost continuata si de procesoarele care au urmat (80486, Pentium, Pentium Pro, Pentium II, Pentium III, Pentium IV), astfel incat astazi familia procesoarelor Intel pe 32 biti are in urma o istorie bogata. In cele ce urmeaza vom creiona noutatile aduse de procesoarele pe 32 biti.

Dimensiunea datelor si adreselor

Magistrala de adrese, la fel ca si cea de date, are 32 biti, deci cantitatea maxima de memorie care poate fi accesata este de 4 Go. Desi au aparut deja aplicatii al caror necesar de memorie depaseste si aceasta valoare, saltul de la 1 Mo este mai mult decat semnificativ. Ca dovada, au trecut aproximativ doua decenii de la lansarea microprocesorului 80386 si marea majoritate a programelor inca nu au probleme cu limita de memorie.



Corespunzator, dimensiunea registrilor a crescut si ea la 32 biti. De fapt, pentru a se pastra compatibilitatea cu procesoarele pe 16 biti, registrii acestora exista in continuare, exact in forma in care au fost prezentati mai sus. In plus, au fost introdusi o serie de registri noi, pe 32 biti, care ii includ pe cei deja existenti (figura 3.7).

EAX


AH

AL

AX

EBX


BH

BL

BX

ECX


CH

CL

CX

EDX


DH

DL

DX

ESP




SP

EBP




BP

ESI




SI

EDI




DI

Fig. 3.7.

Fiecare registru pe 32 biti include, la partea mai putin semnificativa, unul dintre registrii pe 16 biti, iar numele sau este format din numele registrului vechi, adaugandu-i-se in fata litera E (extended). Astfel, noii registri generali ai procesorului sunt EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI. Denumirile de registri de date, index si pointer isi pierd practic semnificatia, deoarece noii registri sunt complet interschimbabili, adica nu mai exista diferente intre ei cu privire la operatiile la care pot fi folositi.

Registrul IP (pointerul de instructiuni al procesoarelor pe 16 biti) este inclus intr-un registru de 32 biti, numit desigur EIP. Acesta din urma indeplineste acum rolul de pointer de instructiuni. In plus, registrul indicatorilor de conditii (FLAGS) este la randul sau extins la un registru de 32 biti (EFLAGS). Nu vom intra insa in detalii privitoare la indicatorii de conditii suplimentari.

Exista si o exceptie de la regula extinderii. Registrii de segment raman la dimensiunea de 16 biti, fara a fi creati registri noi. In schimb sunt adaugati doi registri de segment noi, tot pe 16 biti, numiti FS si GS (figura 3.8). Acestia nu au un rol anume, ci pot fi folositi pentru accesarea datelor, la fel ca DS sau ES.


CS


DS


SS


ES


FS


GS

Fig. 3.8.

In final, facem observatia ca noii registri nu sunt intotdeauna disponibili. Orice microprocesor Intel pe 32 biti are doua moduri diferite de functionare:

- modul real, in care functioneaza la fel ca un procesor pe 16 biti

- modul protejat, in care se poate lucra cu registrii de 32 biti

Modul real a fost pastrat pentru compatibilitatea cu aplicatiile mai vechi. Trecerea microprocesorului dintr-un mod de functionare in altul poate fi controlata prin software.

Coprocesorul matematic

Incepand cu microprocesorul 80486, coprocesorul matematic a fost inclus in unitatea centrala de procesare, nemaifiind un circuit separat. Aceasta reprezinta o consecinta logica a evolutiei tehnologiei, care a permis o crestere a numarului de tranzistoare pe o pastila de siliciu (prin scaderea dimensiunii acestora), dar si o recunoastere a importantei calculelor in virgula mobila in cadrul aplicatiilor. Prin integrarea coprocesorului matematic in acelasi circuit cu microprocesorul s-a obtinut un spor de performanta datorat scrutarii cailor de semnal si simplificarii comunicarii intre componente.

Pipeline

O alta imbunatatire importanta este data de perfectionarea structurii de tip pipeline. Asa cum am vazut mai sus, la procesoarele pe 16 biti unitatea de prelucrare este impartita in unitatea de interfata cu magistrala (BIU), care se ocupa de aducerea in avans a instructiunilor din memorie si depunerea lor intr-o coada, si unitatea de executie (EU), care preia instructiunile din coada si le executa. Aceasta impartire permite lucrul in paralel al celor doua unitati, ceea ce se traduce printr-o functionare mai rapida. La procesoarele pe 32 biti ideea a fost dusa si mai departe. Dupa cum ne amintim, fiecare instructiune consta din 4 faze (adresare, citire, decodificare, executie). Mai mult, fiecare din aceste faze (mai ales cea de executie, care este cea mai complexa) poate consta la randul sau din mai multe operatii mai simple. Ideea este ca fiecare din aceste operatii lucreaza in principiu cu alte resurse, deci toate operatiile se pot executa in paralel. Astfel, executia unei instructiuni poate fi impartita intr-un numar mare de actiuni elementare, numite stagii ale pipeline-ului. Deci, la un moment dat se pot afla in executie in procesor mai multe instructiuni, in diferite faze; in cazul cel mai fericit exista cate o instructiune tratata in fiecare stagiu al pipeline-ului. Desi executia unei instructiuni de la inceput pana la sfarsit necesita un numar mare de actiuni, o instructiune poate incepe sa fie executata imediat ce instructiunea anterioara a trecut de primul stagiu.

De ce este atat de eficienta aceasta structura? Activitatea procesorului este coordonata cu ajutorul semnalului de ceas al sistemului. Trecerea executiei unei instructiuni de la un stagiu la altul se poate face numai atunci cand 'bate' ceasul, deci la intervale regulate de timp. Pe de alta parte, fiecare actiune elementara (stagiu) se executa intr-o anumita durata finita de timp. Daca semnalul de ceas este prea rapid, actiunile nu se mai pot realiza pe durata dintre doua 'batai' ale ceasului, ceea ce ar duce la pierderea controlului asupra executiei instructiunilor. Ca urmare, frecventa ceasului nu poate fi crescuta oricat de mult, ci este limitata de duratele de executie ale stagiilor. Daca actiunile elementare sunt mai simple (ceea ce implica o descompunere mai fina a instructiunilor si deci un numar de stagii mai mare), ele vor consuma mai putin timp; implicit, frecventa ceasului va putea fi crescuta. Daca analizam functionarea unui pipeline, observam ca, in cazul cel mai fericit, la fiecare 'bataie' a ceasului se poate termina de executat cate o instructiune, deci performanta procesorului depinde direct de cresterea frecventei semnalului de ceas.

Procesoarele Intel au evoluat in sensul cresterii continue a numarului de stagii a pipeline-ului. La ultimele microprocesoare Pentium IV s-a ajuns la un pipeline cu 32 stagii, ceea ce este mult mai mult decat oricare varianta anterioara. Cu alte cuvinte, executia unei instructiuni a microprocesorului este impartita in 32 operatii elementare. Pentru microprocesoarele cu numar foarte mare de stagii se foloseste si denumirea de unitati superpipeline.

Totusi, structura de tip pipeline are si dezavantaje. Ideea sa de pornire este ca fiecare stagiu lucreaza cu alte resurse ale procesorului decat restul stagiilor. Aceasta cerinta nu poate fi niciodata satisfacuta in totalitate. Ca un exemplu simplu, o operatie de adunare necesita folosirea unitatii aritmetico-logice (ALU) pentru efectuarea calculului propriu-zis. In acelasi timp, in faza de adresare a unei instructiuni, valoarea registrului indicator de instructiuni (IP la procesoarele pe 16 biti) este incrementata, pentru a putea aduce codul urmatoarei instructiuni. Deoarece incrementarea este tot o operatie de adunare, va fi nevoie tot de ALU. Astfel, o instructiune de adunare aflata in faza de executie si o alta instructiune aflata in faza de adresare vor concura pentru aceeasi resursa (ALU). Asemenea situatii apar de fapt mult mai des, deoarece intre instructiuni exista relatii de dependenta rezultate din insasi logica programului. Se intampla foarte des ca o instructiune sa aiba nevoie de rezultatul unei instructiuni anterioare, care inca nu l-a calculat. Din acest motiv, de multe ori o instructiune (si implicit cele care urmeaza dupa ea) trebuie sa astepte pana cand devine disponibila o resursa de care are nevoie, dar care este momentan folosita de alta instructiune. Dupa cum am vazut, o asemenea resursa poate fi fie o componenta hardware a procesorului, fie rezultatul altei instructiuni. Ca urmare, in practica se intampla rareori ca procesorul sa termine de executat cate o instructiune la fiecare 'bataie' a ceasului, deci castigul de performanta nu este atat de mare cat speram.

O concluzie importanta care se desprinde de aici este ca simpla lungime a pipeline-ului (adica numarul de stagii) nu este singurul factor care influenteaza performanta procesorului. Impartirea corecta a instructiunilor in operatii elementare poate fi la fel de importanta. Din pacate, aceasta alegere nu poate fi facuta ca urmare a unor consideratii teoretice sau a unor criterii clare, fiind in mare masura o problema de inspiratie. In practica se poate vedea cum microprocesoarele AMD, care sunt compatibile cu cele Intel la nivel de limbaj, dar au o implementare diferita pentru pipeline (care este mult mai scurt), reusesc sa obtina performante asemanatoare, desi lucreaza la frecvente mult mai mici. O solutie deja folosita de procesoarele actuale (atat Intel, cat si AMD) este existenta a doua sau mai multe pipeline-uri; astfel se pot executa mai multe instructiuni in paralel, atunci cand dependentele dintre instructiuni nu introduc perioade de asteptare. Procesoarele care utilizeaza mai multe pipeline-uri se numesc superscalare.

Lucrul cu segmente de memorie

In conditiile in care spatiul de memorie accesibil microprocesorului a crescut pana la 4 Go, segmentele de 64 Ko, cu care lucrau procesoarele pe 16 biti, sunt evident anacronice. Procesoarele pe 32 biti au pastrat conceptul de segment de memorie, dar intr-un mod adaptat necesitatilor.

Sistemele actuale permit executarea simultana a mai multor programe. O consecinta imediata este ca mai multe programe se pot afla simultan in memorie, de unde apare si riscul ca doua sau mai multe asemenea programe sa incerce sa utilizeze (in scopuri diferite) aceeasi adresa de memorie. Evident, asemenea situatii sunt de natura sa duca la interferente nedorite intre programe, cu efecte dintre cele mai grave, de aceea trebuie evitate prin orice mijloace.

Solutia de principiu consta in a introduce o separare intre adresele pe care un program crede ca le acceseaza si adresele utilizate in realitate. Altfel spus, atunci cand un proces incearca sa acceseze o locatie aflata la o anumita adresa, accesul in memoria principala se produce la alta adresa. In continuare, adresele pe care un proces crede ca le acceseaza vor fi numite adrese virtuale, iar adresele accesate in realitate - adrese fizice. Astfel, fiecare proces are la dispozitie un spatiu de adrese (virtuale) propriu, independent de spatiile de adrese ale celorlalte procese. La prima vedere nu se intrevede nici un castig, ci dimpotriva. Totusi, printr-o gestionare atenta a corespondentelor intre adresele virtuale ale fiecarui proces si adresele fizice accesate in realitate, se poate obtine efectul dorit: mai multe programe acceseaza acelasi adrese (virtuale), fara a se produce suprapuneri in memoria fizica. Avantajul obtinut astfel este ca o aplicatie nu mai trebuie sa tina cont de problema interferentelor, ci se poate executa ca si cum toata memoria ar fi la dispozitia sa.

Sa vedem cum se poate folosi lucrul cu segmente pentru a gestiona adresele virtuale si fizice. Dupa cum am aratat, adresa unui octet dintr-un segment se compune din doua parti independente: adresa de inceput (de baza) a segmentului si deplasamentul octetului in interiorul segmentului (numit si offset). Deci, orice adresa poate fi scrisa printr-o pereche de forma: (adresa_baza_segment, deplasament). Aceasta pereche este de fapt o adresa virtuala, deoarece este transformata de procesor intr-o adresa fizica.

Sa analizam ce se intampla in momentul in care doua programe diferite incearca sa acceseze aceeasi adresa virtuala. Adresa de baza a unui segmentului este precizata prin intermediul unui registru de segment. Deci, pentru a evita suprapunerea, este suficient ca valoarea registrului de segment sa fie diferita pentru cele doua programe. Desigur, gestiunea valorilor registrilor de segment nu cade in seama programelor, ci este realizata de sistemul de operare, singurul care are o vedere de ansamblu asupra tuturor aplicatiilor ce ruleaza pe calculator. In acest mod, programele nu trebuie sa opereze nici o modificare pentru arezolva problema.

Totusi, problema nu este inca rezolvata complet, intrucat este necesara stocarea informatiilor referitoare la valorile registrilor de segment pentru fiecare program. In plus, pot aparea si erori de alta natura. De exemplu, orice segment are o anumita dimensiune. Procesoarele pe 32 biti permit ca fiecare segment sa ocupe pana la 4 Go, dar in practica fiecare segment va avea o dimensiune impusa de cantitatea de informatie (date, instructiuni) pe care o contine. Este deci posibil ca deplasamentul sa fie prea mare, astfel incat adresa fizica rezultata sa fie in afara segmentului. Mai mult, fiecare segment poate fi folosit in general de un singur program; trebuie deci evitat ca alt program sa acceseze respectivul segment. Toate aceste situatii trebuie detectate, iar programele care incearca sa realizeze un acces incorect trebuie oprite.

Pentru aceasta, fiecarui segment existent in memorie i se asociaza o structura de date numita descriptor de segment. Principalele informatii continute de acesta sunt urmatoarele:

- adresa de inceput a segmentului

- dimensiunea segmentului

- drepturi de acces la segment

Toti descriptorii de segment sunt grupati intr-un tabel, astfel incat pentru a putea identifica un segment este suficient sa fie cunoscut indicele descriptorului sau in tabel. In acest moment, adresele devin perechi de forma: (indice_descriptor, deplasament). Cu alte cuvinte, registrul de segment nu va mai contine adresa de baza a segmentului, ci indicele acestuia in tabloul descriptorilor. Acesta este motivul pentru care registrii de segment au ramas la dimensiunea de 16 biti, in timp ce adresele sunt pe 32 biti.

Concret, in momentul in care un program incearca sa acceseze o adresa de memorie (data in forma de mai sus), au loc urmatoarele actiuni:

- se verifica in descriptorul segmentului drepturile de acces, pentru a se decide daca programul are dreptul de a accesa adresa dorita

- se verifica daca deplasamentul nu depaseste dimensiunea segmentului

- daca se produce o eroare la unul din pasii anteriori, accesul programului la adresa de memorie solicitata este oprit

- daca nu s-a produs nici o eroare, se calculeaza adresa fizica si se realizeaza accesul propriu-zis

Desigur, toate aceste verificari si calcule nu sunt realizate prin software, ci direct in hardware de catre microprocesor. Este vorba de o activitate complexa, astfel incat procesorul a fost dotat cu o componenta specializata, numita unitate de management al memoriei (Memory Management Unit - MMU).

Paginarea memoriei

Utilizarea segmentarii nu este lipsita de probleme. Deoarece un segment ocupa intotdeauna o zona continua in memoria fizica, atunci cand este creat acesta trebuie plasat intr-o zona libera suficient de mare. La un moment dat, datorita diverselor alocari si eliberari de segmente, memoria arata ca un sir de zone ocupate si libere, de diferite dimensiuni. Experienta arata ca in timp se ajunge la aparitia unui numar mare de zone libere de dimensiuni foarte mici, practic inutilizabile. Procesul de formare a acestor zone libere, care nu pot fi folosite din cauza dimensiunilor prea reduse, poarta numele de fragmentare externa. Este posibil in acest fel ca un segment sa nu mai poata fi plasat in memorie, desi dimensiunea totala a zonelor libere este mai mare decat dimensiunea segmentului respectiv.

O abordare alternativa, in general mai eficienta, poarta numele de paginare a memoriei. Ideea este de a stabili o corespondenta mai directa intre adresele virtuale si adresele fizice decat in cazul segmentarii. Astfel, spatiul de adrese virtuale ale unui program este impartit in zone de dimensiuni egale (uzual 4-8 Ko), numite pagini (pages). Similar, memoria fizica este impartita in zone de aceeasi lungime, numite cadre de pagina (page frames). Sistemul de operare construieste in memorie, pentru fiecare proces, un tabel, numit tabel de paginare, care va contine paginile apartinand procesului si cadrele de pagina corespunzatoare in memoria fizica. In cazul paginarii, adresele virtuale sunt valori pe 32 biti, exact ca adresele fizice.

Practic, lucrurile se desfasoara astfel:

- De fiecare data cand programul incearca un acces la o adresa virtuala, MMU determina pagina din care face parte respectiva adresa si o cauta in tabelul de paginare.

- Daca pagina se afla in tabelul de paginare, se determina cadrul de pagina corespunzator si se calculeaza adresa fizica. Abia in acest moment se realizeaza accesul propriu-zis la locatia de memorie dorita.

- Daca pagina nu se gaseste in tabelul de paginare, avem o incercare de acces ilegal la memorie, eroare numita uzual defect de pagina (page fault). La fel ca la segmentare, in cazul detectarii unei erori, accesul la memorie nu se mai realizeaza.

Sa luam ca exemplu un tabel de paginare avand urmatoarea structura:

Adrese virtuale

0

1

2

4

5

Adrese fizice

0

2

3

1

6

Consideram pentru simplitate ca dimensiunea unei pagini este de 100 octeti. In acest caz, pagina 0 va contine adresele virtuale 0-99, pagina 1 adresele 100-199, pagina 2 adresele 200-299 etc. Similara este relatia dintre cadrele de pagina si adresele fizice.

Presupunem ca programul incearca sa acceseze adresa 124. Aceasta face parte din pagina 1, careia ii corespunde in tabel cadrul de pagina 2. Astfel, in realitate va fi accesata adresa fizica 224. Daca programul incearca sa acceseze adresa 367, MMU observa ca pagina 3, din care face parte acea adresa, nu apare in tabelul de paginare, deci este un acces ilegal.

Deoarece o zona de memorie oricat de mare poate fi impartita in pagini de dimensiune fixa, ce pot fi raspandite in memorie in orice mod, nu apare fenomenul de fragmentare externa. In schimb se intalneste fragmentarea interna: deoarece dimensiunea paginilor este fixa, iar zonele de memorie cu care lucreaza procesele pot avea orice dimensiune, in general la sfarsitul unei pagini ramane o zona nefolosita. Din acest motiv, dimensiunea paginilor de memorie este stabilita ca un compromis intre doua cerinte contradictorii:

- o dimensiune prea mare a paginii provoaca o fragmentare interna puternica

- o dimensiune prea mica a paginii duce la ocuparea unui spatiu prea mare de catre tabelele de paginare, micsorand memoria care poate fi folosita de aplicatii

Daca dimensiunea paginii este bine aleasa, fragmentarea interna este in general mai redusa decat cea externa (aparuta in cazul segmentarii).

Exista si posibilitatea de a folosi simultan segmentarea si paginarea memoriei. Este insa vorba de o tehnica rar folosita in practica, din cauza complexitatii sale, astfel incat nu vom insista asupra ei.