<docere>http://www.docere.ro/ |

Accesarea memoriei; regiştri ai microprocesorului
Memoria internă are un rol pasiv: păstrează informaţii. Recunoaşterea şi procesarea propriu-zisă a informaţiei respective este sarcina microprocesorului, desemnat de obicei prin CPU; acesta dispune prin construcţia sa, de un set intern de instrucţiuni ("limbajul maşinii") care pot să fie folosite de către sistemele de operare şi de către aplicaţii pentru gestionarea traficului informaţiei şi realizarea operaţiilor asupra datelor.
Această sarcină este asigurată material în primul rând, prin conectarea CPU cu memoria internă; comunicarea se face prin trei magistrale comune: una pentru adrese, una pentru date şi una destinată altor semnale (de comandă, control, stare). Într-o accepţie simplă, o magistrală (sau bus) ar fi constituită din una sau mai multe "sârme" paralele, pe care circulă semnale electrice de anumite nivele standard; unele nivele de semnal electric sunt interpretate fie ca "1", fie ca "0" (de exemplu, o linie pe care circulă un semnal de 0.0 - 0.8V reprezintă "0", iar una cu semnal 2.4 - 5V reprezintă "1"; un semnal de 0.8-2.4V poate indica o tranziţie în curs pe linia respectivă, de la "0" la "1" sau invers).
Magistrala de adrese este alcătuită dintr-un anumit număr de "linii de adresă" A0, A1, A2, ..., An; semnalele emise pe aceste linii constituie împreună adresa absolută a unei locaţii de memorie şi semnalele respective determină selectarea acelei locaţii, făcând posibile operaţiile de citire/înscriere a conţinutului ei:

Cum realizează CPU operaţia de scriere în memorie (adică înscrierea unui octet într-o anumită locaţie de memorie, sau a unui cuvânt de 16/32/64 biţi în 2/4/8 locaţii consecutive)? În principiu, prin emiterea pe magistrale a semnalelor corespunzătoare, într-o anumită succesiune:
— se aplică adresa locaţiei pe magistrala de adrese;
— se depune cuvântul de date pe magistrala de date;
— se activează semnalul de comandă a scrierii; ca urmare, cuvântul existent pe magistrala de date va "intra" în locaţia a cărei adresă a fost aplicată pe magistrala de adrese;
— se dezactivează semnalul de scriere;
— se "eliberează" magistralele de date şi de adrese.
Este clar că se va putea selecta o anumită locaţie de memorie, numai dacă adresa acesteia "încape" în magistrala de adrese; de exemplu, dacă ar fi numai 4 linii de adresă, atunci s-ar putea accesa direct numai locaţiile de la adresele 0..15 - fiindcă adresa 16 = 100002 deja ar depăşi lăţimea de 4 biţi asumată aici. Primele microprocesoare pe 8 biţi (Intel 8080 în 1974, apoi Zilog Z80) aveau magistrala de adrese de 16 linii - permiţând adresarea directă a unei memorii de capacitate 216 = 64Ko; apoi, I8086 lărgeşte magistrala de adrese la 20 de linii, putând adresa direct 220 = 1Mo locaţii distincte; în 1982 Intel 80286 o extinde la 24 de biţi, iar apoi I80486 şi Pentium o extind la 32 de biţi.
Este foarte importantă de asemenea, lăţimea magistralei de date. Pentru a permite în modul descris mai sus, transferul unui octet - magistrala de date trebuie să aibă cel puţin 8 linii; dar, dacă ar avea numai 8 linii (cazul I8080), atunci pentru a transfera un grup de doi octeţi sunt necesare două operaţii distincte - pe când dacă are 16 biţi (I8086, I80286; 32 biţi pentru I80486) atunci este posibil transferul simultan a doi octeţi (într-o singură operaţie).
Asigurarea lăţimii de 16 / 32 / 64 biţi pentru magistrale permite considerarea, pe lângă octet (sau byte) - care este conţinutul unei singure locaţii de memorie, deci are 8 biţi lungime - şi a datelor multi-octet; se numeşte word o dată constituită prin "alipirea" a din doi octeţi şi dword o dată constituită din 4 octeţi (32 de biţi).
Pentru a permite operarea într-un acelaşi mod asupra unor date "multi-octet", a trebuit să se aleagă una din cele două posibilităţi privind ordinea depunerii în memorie a octeţilor componenţi: convenţia little-endian - adoptată de Intel - consideră că octetul mai semnificativ este memorat în locaţia cu adresa mai mare (altfel spus, semnificativitatea octetului creşte odată cu adresa de memorie); convenţia inversă, big-endian (în care, octetul mai semnificativ este primul, adică este memorat la adresa mai mică) este întâlnită de exemplu la microprocesoarele Motorola 68000.
De exemplu, am putea spune pentru analogie că 2008-04-18 reprezintă o dată calendaristică în format "big-endian", iar 18-04-2008 reprezintă aceeaşi dată în format "little-endian".
Un word oarecare, având 16 biţi - rezultă prin concatenarea a două secvenţe de câte 8 biţi (a doi octeţi); valoarea maximă a unui octet este 111111112 = FF16 = 255, deci valoarea maximă a unui word este FFFF16 = (FF16)(FF16)256 = (255)(255)256 = 255*256 + 255 = 65535 = 216-1. Oricărui word W = 0..216-1, i se poate asocia un tablou de două locaţii consecutive (L[0], L[1]) încât W = L[0] + 256 * L[1] — anume, luând L[0] = W mod 256 şi L[1] = W div 256 (unde "a mod b" şi "a div b" desemnează restul şi respectiv câtul împărţirii lui a prin b). L[0] este cifra low (cea mai puţin semnificativă), iar L[1] este cifra high din reprezentarea lui W în baza 256.
Spre exemplu, să vedem cum se reprezintă în memorie numărul 1234; faţă de baza 216 avem 1234 = 4 * 256 + 210 = (4)(210)256, deci în memorie am avea:
| adresă | conţinut | |
|---|---|---|
| ... | ... | |
| A | 210 | (octetul low) |
| A + 1 | 4 | (octetul high) |
| A + 2 | ... |
Cum 210 = 14 * 16 + 2 = (14)(2)16 = 1110200102 = 111000102 avem în final, următorul tablou de memorie:
| adresa A - 1 | A | A + 1 | adresa A + 2 |
| --- | 11100010 | 00000100 | --- |
Observaţie: reprezentarea în memorie nu coincide cu reprezentarea binară obişnuită. Astfel, reprezentarea în baza 2 cu 16 cifre binare obţinută mai sus este 1234 = 00000100111000102, ori în memorie cele 8 cifre de la sfârşitul reprezentării binare compun octetul low, de adresă A, iar cele 8 cifre binare iniţiale constituie octetul high, de adresă A + 1 (în memorie, octeţii sunt inversaţi faţă de ordinea "firească").
Memoria este accesată prin intermediul magistralelor, pe unităţi de un octet, un word, sau un dword; adresa unei date multi-octet este dată de adresa celui mai puţin semnificativ octet al ei (se subînţelege - peste tot aici, folosim convenţia "little-endian"); în exemplul de mai sus, word-ul 1234 conţinut în locaţiile de adrese A, A + 1 are adresa A. Deci pentru a citi data respectivă, trebuie ca pe magistrala de adrese să se depună adresa octetului low al ei.
Să zicem ca magistrala de date are lăţimea de 16 biţi. Transferul unui octet are loc pe oricare dintre cele două jumătăţi ale căii de date, însă: dacă A0 = 0 (adică adresa octetului respectiv este număr par), atunci octetul este transferat pe liniile D7 - D0 (jumătatea inferioară a căii de date), iar dacă A0 = 1 (adică octetul respectiv are adresa impară), atunci el este transferat pe D15 - D8 (jumătatea superioară a căii de date).
Ca urmare a acestei reguli, s-a creat posibilitatea ca un word care are octetul low la adresă pară (A0 = 0) să fie transferat pe D15 - D0 într-un singur ciclu (octetul low fiind depus pe D7 - D0 ca având adresa pară, iar octetul high - de la adresa următoare, deci impară - fiind depus pe D15 - D8 — încât în final se transferă întregul word, în cadrul unei aceleiaşi operaţii de transfer).
În schimb, dacă A0 = 1 (word-ul are adresă impară), atunci vor fi necesare două operaţii succesive (cu remediul că ele sunt înlănţuite automat): se transferă întâi octetul low pe D15 - D8 şi apoi şi octetul high (de adresă pară) pe D7 - D0.
Avem justificată astfel, opţiunea (directiva) word align data oferită de compilatoare sau de asambloare (în baza căreia, datele vor fi aliniate în memorie la adrese pare - mărind prin aceasta, viteza accesării lor).
CPU fiind exterior memoriei, ar fi de imaginat că pentru a face o operaţie binară, el ar trebui în prealabil să acceseze operanzii respectivi din memorie, prin intermediul magistralelor — ceea ce am văzut ca este totuşi costisitor în privinţa timpului necesar. Acesta ar fi un prim motiv, pentru care microprocesorul conţine el însuşi câteva locaţii interne de memorie, numite regiştri; etapa citirii din memorie prin intermediul magistralelor se va putea eventual elimina, înlocuind-o printr-o încărcare directă în regiştri.
Între "locaţie de memorie" şi "registru al CPU" avem două deosebiri esenţiale. Locaţiile de memorie au în mod explicit, atributul de "adresă"; iar în limbaj de asamblare, pentru a distinge între adresă şi conţinutul locaţiei de la adresa respectivă, folosim parantezele: dacă X este o adresă, atunci [X] (sau, în unele asambloare (X)) este conţinutul locaţiei de la adresa respectivă (analog cum, dacă j este rangul unui element al tabloului V, atunci V[j] este valoarea acelui element). În schimb, regiştrii CPU nu au asociate în mod explicit, adrese; fiind în număr mic, ei sunt referiţi prin mnemonice (AX, BX, EAX, etc.); desigur, acestea sunt utilizabile la nivelul limbajelor de programare, altfel - intern - regiştrii sunt adresaţi prin coduri de 3-4 biţi (de exemplu, 8 regiştri vor fi referiţi prin "adresele" 0002, 0012, 0102, ..., 1112).
A doua deosebire se referă la dimensiune: regiştrii CPU au dimensiunea corelată cu aceea a magistralelor de adrese şi de date; unii regiştri au 8 biţi (ca şi locaţiile de memorie), alţii au 16, 32 sau 64 de biţi; iar regiştrii coprocesorului — FPU, component şi el al CPU, fiind dedicat pentru calcule "în virgulă mobilă" (când numerele sunt reprezentate "segmentat": o parte de exponent si o parte de mantisă) — au dimensiunea standard de 80 biţi.
Microprocesoarele Intel 80x86 dispun de 4 regiştri principali pentru date, denumiţi simplu AX, BX, CX, DX - toţi de tip word; părţile low ale acestora (cuprinzând biţii mai puţin semnificativi, de la rangul 0 la rangul 7) sunt denumite respectiv AL, BL, CL, DL în timp ce părţile high ale lor (biţii de la rangul 8 până la rangul 15) sunt desemnate prin mnemonicele AH, BH, CH, DH.
Microprocesoarele I80386 şi cele ulterioare dispun si de nişte extensii ale acestor regiştri, denumite EAX, EBX, EVX, EDX - toţi de tip dword; de exemplu, AX este acum parte (şi anume, partea low) a lui EAX:

Observaţie: reprezentarea în baza 2 coincide de data aceasta, cu reprezentarea în regiştri; însă corespondenţa între regiştri şi memorie se face asociind părţii low locaţia de adresă mai mică.
Dat fiind că un registru nu mai are asociată explicit o adresă, nu mai este nevoie (ca în cazul locaţiilor de memorie) să indicăm valoarea conţinută de registru prin vreo convenţie specială (precum, folosirea parantezelor); mnemonica registrului va reprezenta însăşi valoarea conţinută de registru. Între valoarea existentă într-un registru de 16 biţi şi valorile subregiştrilor săi de câte 8 biţi, avem relaţii precum:
— AX = 256 * AH + AL
— AH = AX div 256
— AL = AX mod 256
Însă valoarea existentă într-un registru va putea fi interpretată în anumite cazuri, drept adresă de memorie; cu alte cuvinte, în loc să adresăm direct o locaţie de memorie (precizând în mod explicit adresa ei), o vom putea adresa indirect, prin intermediul unui anumit registru care ar conţine adresa locaţiei. În acest caz, conţinutul locaţiei respective va fi redat (la nivelul limbajului de asamblare) prin încadrarea cu paranteze a mnemonicii registrului; de exemplu, dacă avem BX = 1000, atunci notaţia [BX] va desemna nu conţinutul registrului BX (valoarea 1000) - ci valoarea existentă în locaţia de adresă 1000 (sau mai precis, de la offset-ul 1000 într-un anumit segment de memorie). Prin adresarea directă a unei locaţii de memorie (în vederea citirii sau scrierii), adresa ei (cunoscută explicit) este depusă ca atare, pe magistrala de adrese; în schimb, când ea este adresată indirect, de exemplu prin BX (nu ştim adresa ei, ci doar că ea se află în BX) - atunci pe magistrala de adrese se va depune conţinutul registrului respectiv, BX.
Regiştrilor CPU li s-a conferit un rol important în realizarea transferurilor de date. CPU nu asigură transferul direct între locaţii de momorie (nu operează schema "memorie => memorie"), ci doar prin intermediul regiştrilor (după schema "memorie => registru => memorie"). Mai mult, o locaţie de memorie dată explicit prin Segment:Offset (de exemplu, 100:1234) nu poate fi adresată de CPU decât prin intermediul regiştrilor de segment: partea de Segment 100, trebuie înregistrată în prealabil într-un registru de segment de exemplu DS ("Data Segment"), după care locaţia va fi adresată prin DS:Offset (unde Offset poate fi dat ca atare, sau este şi el, dat indirect - indicând un registru care conţine adresa relativă respectivă).
În anul 1978 a apărut un nou membru marcant al familiei de microprocesoare INTEL - anume, I8086; tipurile ulterioare, până la I80486 şi Pentium, au respectat consecvent principiul compatibilităţii în jos - ceea ce a contribuit şi la succesul imediat pe piaţă: adaptarea aplicaţiilor existente, cu care utilizatorul era deja obişnuit, a necesitat cheltuieli minime (aplicaţiile create iniţial pentru I8086 "merg" şi pe Pentium).
Compatibilitatea în jos s-a asigurat prin menţinerea principiilor de adresare a memoriei. I8086 are 20 de pini pentru adresă (altfel spus, are o magistrală de adrese de lăţime 20) - ceea ce asigură adresarea directă a 220 = 16 * 216 locaţii, prin adresele 0x00000, 0x00001, 0x00010, ..., 0xFFFFF de câte 5 cifre hexazecimale (5 cifre × 4 biţi = 20 biţi). Dar iată ce nepotrivire trebuia rezolvată: dimensiunea maximă a regiştrilor era de 16 biţi - ori într-un registru de 16 biţi se pot forma doar adresele 0..216 - 1 (mai precis, se pot adresa 216 locaţii consecutive - un segment oarecare - şi nu neapărat numai cele de la adresele absolute 0..216 - 1).
Pentru a permite adresarea a 220 locaţii consecutive (cât ar permite cele 20 de linii de adresă), s-a adoptat modelul segmentat de memorie: unii regiştri au fost înzestraţi prin proiectarea iniţială, cu funcţia specială de a păstra partea de segment a adresei — anume, regiştrii cu mnemonicele CS, DS, ES, SS (la care, începând cu I80386, s-au adăugat FS si GS - rezultând acum în total, 6 regiştri de segment). Pe de altă parte, s-a încorporat microprocesorului o unitate funcţională care să asigure formarea adreselor fizice de 20 biţi, pe baza componentelor Segment:Offset (unde partea de Segment sa fie conţinută într-un registru de segment).
O adresă de 20 de biţi are 5 cifre hexazecimale, ori un regisru de 16 biţi (cum sunt regiştrii de segment) poate păstra doar 4 cifre hexazecimale; s-a adoptat atunci convenţia ca prima locaţie din oricare segment de memorie să aibă adresa absolută ("adresa de bază" a segmentului) multiplu de 16 - adică ultima cifră din reprezentarea sa hexazecimală să fie zero (4 biţi 0). Registrul de segment va fi încărcat cu numărul dat de primele 4 cifre hexazecimale ale adresei de bază a segmentului respectiv, urmând ca unitatea de formare a adresei fizice să asigure deplasarea spre stânga cu 4 biţi a valorii transmise prin registrul de segment (rezultând astfel adresa de bază a segmentului, cu 5 cifre hexazecimale, dintre care ultima este totdeauna 0x0000) si la valoarea rezultată astfel să adune partea de offset a adresei locaţiei respective (partea de offset fiind dată explicit ca număr 0..216 - 1, sau fiind conţinută de un registru precizat dar care, nu poate fi tot un registru de segment).
Cu alte cuvinte, specificaţia Segment:Offset trebuie adaptată la DS:Offset (unde DS a fost încărcat cu valoarea Segment), sau CS:Offset, etc. Această modalitate de adresare a fost apoi păstrată, doar că - odată cu extinderea magistralelor la 32 biţi şi cu apariţia modului "protected" - s-a putut creşte dimensiunea segmentului de memorie; regiştrii de segment au rămas tot de câte 16 biţi, dar partea de offset poate fi acum de 32 biţi.
ORAR orarul şcolii
SitSco situaţie şcolară
ŞAH prin corespondenţă
doChess a Javascript chess engine
doPGN a Javascript PGN-browser
Cal++ ambiţiile Calului
aşaAzis momente lingvistice
Comentarii
—cum ar trebui calculată Media şcolară?
completely rethink the browser:
Google chrome