Acest curs răspunde la două întrebări cu consecințe practice directe: cum se organizează memoria unui sistem embedded (von Neumann, Harvard, Harvard modificată) și ce anume face procesoarele ARM - de departe cele mai răspândite în microcontrolerele de azi - să arate și să se comporte cum se comportă: registre, pipeline, moduri de operare, întreruperi și cele două seturi de instrucțiuni, A32 și Thumb/Thumb-2.
1Obiectul și structura cursului6 min
Până acum am discutat despre ce este un sistem embedded și cum se măsoară performanța unui procesor „la nivel abstract" (ISA, CPI, IPC). Astăzi coborâm încă un etaj: cum arată, concret, memoria unui microcontroler și cum e organizat procesorul care o accesează - cu accent pe familia ARM, prezentă în marea majoritate a microcontrolerelor moderne.
- ISA separă software-ul vizibil programatorului de implementarea hardware internă
- RISC (instrucțiuni simple, lungime fixă, load/store) domină sistemele embedded datorită eficienței energetice și simplității de implementare
- Performanța reală se calculează, nu se ghicește din frecvență: Execution Time = IC × CPI × Clock Cycle
Rezultate ale învățării
- Să explicați diferența dintre arhitecturile von Neumann, Harvard și Harvard modificată
- Să identificați profilul ARM (A, R sau M) potrivit unei aplicații date
- Să localizați rolul registrelor R0-R15 într-un cod ARM/Cortex-M simplu
- Să explicați cum funcționează un pipeline de trei etape și de ce un salt îl „golește"
- Să citiți indicatorii N, Z, C, V dintr-un registru de stare și să anticipați un salt condiționat
- Să explicați de ce Thumb/Thumb-2 există și ce compromis rezolvă
2Arhitectura von Neumann10 min
Avantajul principal e flexibilitatea: spațiul de memorie poate fi împărțit dinamic între program și date, fără ca dimensiunea celor două regiuni să fie fixată de hardware. Un singur spațiu de adrese simplifică modelul de programare - codul poate fi tratat ca informație memorată, la fel ca orice altă dată.
Pentru a calcula suma a două valori din memorie, procesorul trebuie: (1) să preia instrucțiunea, (2) să citească cei doi operanzi, (3) să scrie rezultatul. Dacă toate aceste transferuri trec prin aceeași interfață de memorie, ele concurează pentru aceeași resursă - chiar dacă adunarea în sine durează un singur ciclu ALU, timpul total poate fi dominat de accesările memoriei.
3Arhitectura Harvard10 min
Separarea permite procesorului să preia instrucțiunea următoare în același timp în care instrucțiunea curentă citește sau scrie un operand - accesul la program nu mai concurează cu accesul la date. Proprietatea e valoroasă mai ales în procesoarele cu pipeline și în aplicațiile care procesează repetitiv fluxuri de date (DSP-uri).
Separarea fizică permite și adaptarea fiecărei memorii la rolul ei: memoria de program poate folosi o tehnologie nevolatilă (Flash), cu un cuvânt suficient de lat pentru o instrucțiune completă, iar memoria de date poate folosi SRAM rapid, optimizat pentru citiri/scrieri frecvente - exact combinația Flash+RAM din orice microcontroler modern.
Un microcontroler are 256 KB Flash pentru program și 64 KB SRAM pentru variabile. Chiar dacă aplicația folosește doar jumătate din Flash, spațiul rămas nu poate fi transferat automat către SRAM pentru extinderea stivei - cele două memorii au spații de adresare separate. Aceasta e prețul plătit pentru accesul simultan.
Deoarece programul și datele ocupă spații de adrese diferite, procesorul nu poate, în mod obișnuit, accesa memoria de program cu aceleași instrucțiuni folosite pentru date - constantele, tabelele de căutare și actualizarea firmware-ului au nevoie de mecanisme dedicate.
4Harvard modificată și comparația modelelor11 min
Separarea strictă îmbunătățește debitul, dar reduce flexibilitatea software-ului; memoria complet unificată e ușor de programat, dar reintroduce concurența la accesare. Arhitectura Harvard modificată urmărește combinarea avantajelor ambelor: nu există o singură implementare universală, dar varianta cea mai comună în procesoarele moderne păstrează un spațiu de memorie unificat la nivel de program, cu cache-uri separate pentru instrucțiuni (I-cache) și date (D-cache) aproape de nucleu.
Când programul scrie o zonă de memorie care urmează să fie executată ca și cod (de exemplu, la încărcarea unui firmware nou), datele scrise pot rămâne temporar doar în D-cache, în timp ce I-cache păstrează încă o copie veche. Software-ul de sistem trebuie să sincronizeze și să invalideze explicit cache-urile înainte de a sări în codul nou - o sursă clasică de bug-uri greu de reprodus în sistemele care fac actualizări OTA.
| Caracteristică | von Neumann | Harvard | Harvard modificată |
|---|---|---|---|
| Organizarea memoriei | comună | distincte | separare doar la anumite niveluri |
| Acces concurent | limitat | simultan | simultan prin I-cache/D-cache |
| Spații de adrese | unificat | separate | unificat, cu căi separate local |
| Flexibilitate | ridicată | mai redusă | ridicată, hardware mai complex |
| Utilizări reprezentative | model conceptual clasic | DSP-uri, microcontrolere stricte | majoritatea procesoarelor moderne |
5Familia de procesoare ARM10 min
ARM este, de departe, cea mai răspândită familie de arhitecturi de procesoare din lume - de la microcontrolere cu resurse minime, până la telefoane, sisteme automotive și servere. Succesul e legat de principiile RISC, eficiența energetică și adaptabilitatea la cerințe foarte diferite. Denumirea a pornit de la Acorn RISC Machine (anii 1980), apoi Advanced RISC Machines; astăzi se folosește „Arm".
ARM (compania) nu fabrică procesoare - licențiază arhitecturi și nuclee de procesare producătorilor de circuite integrate. De aceea două microcontrolere diferite pot folosi același nucleu Cortex-M, dar avea periferice și organizare a memoriei complet diferite - nucleul e doar o piesă din puzzle.
Familia ARM este organizată în trei profiluri arhitecturale, fiecare optimizat pentru o clasă distinctă de sisteme, nu doar „mai mult/mai puțin performant":
| Profil | Domeniu principal | Gestiunea memoriei | Sistem de operare | Exemple |
|---|---|---|---|---|
| Cortex-A (Application) | sisteme cu SO complex | MMU, memorie virtuală, cache avansat | Linux, Android, Windows | telefoane, routere, servere |
| Cortex-R (Real-time) | control critic, determinist | MPU, memorii TCM predictibile | RTOS sau dedicat | automotive, stocare, industrial |
| Cortex-M (Microcontroller) | microcontrolere embedded | MPU opțională, fără MMU clasică | bare-metal sau RTOS | IoT, senzori, controlere |
În acest curs ne concentrăm pe elementele modelului clasic AArch32 (util pentru a înțelege evoluția arhitecturii) și pe particularitățile Cortex-M - cel mai relevant profil pentru sistemele embedded pe care le construiți în laborator.
6Registrele arhitecturii ARM11 min
Registrele sunt cel mai rapid spațiu de stocare disponibil procesorului - păstrează operanzii, adresele de memorie și informațiile de control ale execuției. Folosirea eficientă a registrelor reduce numărul de accesări ale memoriei principale și crește direct performanța.
Modelul clasic AArch32: R0-R15
| Registru | Rol |
|---|---|
| R0-R3 | parametri de funcție și valori de retur |
| R4-R11 | variabile locale, conservate între apeluri de funcții |
| R12 | registru temporar (folosit de compilator / linker) |
| R13 (SP) | Stack Pointer - vârful stivei curente |
| R14 (LR) | Link Register - adresa de întoarcere dintr-un apel de funcție |
| R15 (PC) | Program Counter - adresa instrucțiunii curente/următoare |
BL functie ; salvează adresa de întoarcere în LR, sare la "functie" ; ... continuarea programului ... functie: ADD R0, R0, #1 BX LR ; revine folosind adresa din LR
Dacă funcția apelează, la rândul ei, altă funcție, trebuie să salveze LR pe stivă înainte, altfel adresa de întoarcere originală se pierde:
functie:
PUSH {R4, LR}
MOV R4, R0
BL alta_functie
ADD R0, R0, R4
POP {R4, PC} ; încărcarea direct în PC realizează revenireaParticularități Cortex-M
Cortex-M păstrează R0-R15 cu roluri similare, dar introduce două indicatoare de stivă distincte: MSP (Main Stack Pointer), folosit după resetare și în Handler Mode, și PSP (Process Stack Pointer), folosit de aplicație sau de task-urile unui RTOS. Separarea izolează stiva nucleului/rutinelor de excepție de stivele folosite de aplicație - o protecție utilă atunci când o eroare de aplicație nu trebuie să corupă gestiunea excepțiilor sistemului.
7Program Counter și execuția în pipeline10 min
Registrul PC conține adresa instrucțiunii următoare. Într-un procesor fără pipeline, valoarea lui ar corespunde direct instrucțiunii aflate în execuție. Într-un procesor cu pipeline - toate procesoarele ARM moderne - mai multe instrucțiuni se află simultan în etape diferite, iar semnificația exactă a valorii citite din PC depinde de organizarea arhitecturii.
Această observație explică o regulă practică din programarea embedded: codul cu multe salturi condiționate imprevizibile poate fi mai lent decât „numărul de instrucțiuni" ar sugera - pipeline-ul plătește o penalizare la fiecare salt greșit anticipat.
8Registrele de stare CPSR și xPSR10 min
Pe lângă registrele generale, procesoarele ARM păstrează informația de stare - indicatori rezultați din operații aritmetice, nivel de privilegiu, stare a mecanismelor de control - în registre dedicate. Structura diferă între modelul clasic AArch32 și Cortex-M.
CPSR (Current Program Status Register) - AArch32 clasic
| Indicator | Semnificație |
|---|---|
| N | rezultatul are bitul de semn activ (negativ) |
| Z | rezultatul operației este zero |
| C | operația a produs transport (carry) sau împrumut |
| V | operația cu semn a produs depășire aritmetică (overflow) |
CMP R0, #0 ; scădere "fantomă": actualizează N,Z,C,V fără să memoreze rezultatul BEQ valoare_zero ; salt executat doar dacă indicatorul Z e setat
Dacă R0 conține valoarea zero, indicatorul Z se activează, iar saltul condiționat se
execută - exact mecanismul din spatele oricărui if compilat pentru ARM.
xPSR - Cortex-M
Cortex-M reunește conceptual aceeași informație în registrul xPSR, compus din trei componente: APSR (indicatorii N, Z, C, V, cu rol identic celor din CPSR), IPSR (numărul excepției/întreruperii active) și EPSR (starea execuției). Diferența esențială: Cortex-M nu folosește câmpul de „mod" din CPSR și nici modurile IRQ/FIQ/Supervisor din AArch32 clasic - are propriul model, mai simplu, discutat în secțiunea următoare.
9Moduri de operare și gestionarea întreruperilor10 min
Moduri de operare
Modelul clasic AArch32 definește mai multe moduri de procesor: User (neprivilegiat) și modurile privilegiate System, Supervisor, IRQ, FIQ, Abort, Undefined. Trecerea la un mod de excepție e automată, la apariția evenimentului corespunzător. FIQ e conceput pentru răspuns rapid și are registre bancate suplimentare - reduce necesitatea de a salva registre generale la intrarea în rutină.
Cortex-M simplifică radical: doar două moduri, Thread Mode (execuția aplicației) și Handler Mode (tratarea excepțiilor, întotdeauna privilegiat). Thread Mode poate fi privilegiat sau nu, în funcție de registrul CONTROL - o organizare potrivită pentru microcontrolere și pentru sistemele de operare de timp real (RTOS) care rulează pe ele.
Gestionarea întreruperilor
Întreruperile permit procesorului să reacționeze la evenimente fără să interogheze continuu starea fiecărui periferic (polling). În loc ca aplicația să verifice constant dacă un timer a expirat, perifericul „cere atenția" procesorului doar când apare evenimentul relevant - economie directă de cicluri și de energie.
Tratarea unei întreruperi urmează, în linii mari, patru pași: (1) suspendarea temporară a programului curent, (2) salvarea contextului necesar reluării lui, (3) execuția rutinei de tratare (ISR), (4) restaurarea contextului și reluarea programului întrerupt. Cortex-M automatizează hardware primii doi pași și ultimul, prin mecanismul de exception entry/exit, ceea ce simplifică semnificativ scrierea unei rutine de întrerupere comparativ cu modelul AArch32 clasic.
10Execuție condiționată, Barrel Shifter, Thumb și AMBA10 min
Închidem privirea de ansamblu asupra arhitecturii ARM cu trei mecanisme care explică densitatea și eficiența codului generat: execuția condiționată, Barrel Shifter-ul, și seturile de instrucțiuni Thumb/Thumb-2.
Execuția condiționată
În codificarea A32, multe instrucțiuni includ un câmp de condiție, atașat ca sufix mnemonicii, permițând executarea unei instrucțiuni doar dacă indicatorii de stare satisfac o condiție - reducând numărul de salturi necesare pentru decizii scurte.
CMP R0, #0 MOVEQ R1, #1 ; executată doar dacă R0 == 0 MOVNE R1, #0 ; executată doar dacă R0 != 0
Setul T32 (Thumb-2) e mai restrictiv: folosește preponderent salturi condiționate directe, iar
unele arhitecturi permit blocul IT (If-Then) pentru condiționarea unei secvențe
scurte de instrucțiuni.
Barrel Shifter
Un bloc hardware care deplasează sau rotește un operand înainte ca acesta să intre în ALU - combinând o deplasare cu o operație aritmetică sau logică, într-o singură instrucțiune.
ADD R0, R1, R2, LSL #2 ; R0 = R1 + 4 × R2
Util direct pentru calculul adresei unui element dintr-un tablou ale cărui elemente ocupă
4 octeți - exact tiparul generat de compilator la un acces tablou[i].
| Operație | Nume complet | Comportament |
|---|---|---|
| LSL | Logical Shift Left | deplasare logică stânga - echivalent × 2ⁿ |
| LSR | Logical Shift Right | deplasare logică dreapta, introduce zerouri |
| ASR | Arithmetic Shift Right | păstrează bitul de semn - împărțire aproximativă la 2ⁿ |
| ROR | Rotate Right | rotație - biții eliminați reintră la celălalt capăt |
Thumb și Thumb-2: densitatea codului
Instrucțiunile A32, deși uniforme, ocupă mereu 32 de biți - programele pot deveni mari, ceea ce costă memorie Flash, consum energetic la transfer și lățime de bandă. Setul Thumb inițial a rezolvat asta cu instrucțiuni de 16 biți (subset compact al funcționalității A32, cu unele restricții de registre și constante). Thumb-2 combină codificări pe 16 și 32 de biți în același set (T32): operațiile frecvente rămân compacte, cele complexe pot folosi codificarea largă când e nevoie.
Toate procesoarele Cortex-M execută T32 - dar nu identic: Cortex-M0/M0+ implementează un subset restrâns, optimizat pentru suprafață și consum minim; Cortex-M3/M4 și nuclee mai performante includ un set Thumb-2 mai bogat și extensii opționale (ex: instrucțiuni DSP pe Cortex-M4). Concluzie practică: cod compilat pentru un Cortex-M4 nu rulează neschimbat pe un Cortex-M0 - compilatorul trebuie configurat explicit pentru nucleul țintă.
Interconectarea AMBA (pe scurt)
Un SoC modern conectează procesorul, memoria, DMA și perifericele printr-o familie de protocoale standardizate de ARM, numită AMBA: AXI pentru interconectări de debit ridicat (procesor, memorie, acceleratoare), AHB/AHB-Lite pentru o magistrală de sistem cu performanță bună și complexitate mai redusă (frecventă în microcontrolerele Cortex-M), și APB pentru periferice simple (GPIO, UART, timere), unde simplitatea și consumul redus contează mai mult decât debitul.
11Erori frecvente5 min
- „Harvard înseamnă mereu două memorii fizic separate, complet izolate." În procesoarele moderne, „Harvard" se referă cel mai des la Harvard modificată: memorie principală unificată, dar căi separate (I-cache/D-cache) aproape de nucleu. Verificați dacă discuția se referă la arhitectura vizibilă programatorului sau la organizarea microarhitecturală internă - de multe ori diferă.
- „CPSR și xPSR sunt același lucru, doar cu nume diferit." Conceptual se suprapun parțial (ambele păstrează N,Z,C,V), dar Cortex-M nu are modurile IRQ/FIQ/Supervisor din AArch32 clasic - modelul de excepții e diferit structural. Când citiți documentație ARM, verificați întâi dacă se referă la profilul clasic A/R sau la Cortex-M - multe confuzii pornesc de aici.
- „Mai puține instrucțiuni Thumb înseamnă mereu cod mai mic." O instrucțiune A32 de 32 de biți poate înlocui două instrucțiuni Thumb de 16 biți - avantajul real depinde de aplicație, compilator și distribuția instrucțiunilor folosite, nu doar de lungimea nominală a codificării. Nu comparați densitatea codului doar din lungimea unei instrucțiuni izolate - măsurați dimensiunea binarului final compilat.
12Rezumat și glosar5 min
Organizarea memoriei (von Neumann, Harvard, Harvard modificată) și arhitectura procesorului (registre, pipeline, moduri, întreruperi, seturi de instrucțiuni) determină, împreună, cât de rapid, previzibil și eficient energetic poate funcționa un sistem embedded. Familia ARM domină azi microcontrolerele tocmai pentru că oferă, prin profilurile A/R/M, soluții adaptate pentru fiecare combinație de cerințe - de la telefoane cu Linux, până la senzori pe baterie fără sistem de operare.
13Întrebări de verificare10 min
- Care este diferența fundamentală dintre arhitecturile von Neumann și Harvard?
- Ce este arhitectura Harvard modificată și de ce e cea mai des întâlnită azi?
- Care sunt cele trei profiluri arhitecturale ARM și pentru ce e optimizat fiecare?
- Care este rolul registrelor SP, LR și PC în modelul AArch32?
- Ce sunt MSP și PSP în Cortex-M și de ce există două stive?
- Cum funcționează un pipeline de trei etape și ce se întâmplă la un salt condiționat?
- Ce indicatori conțin registrele CPSR/xPSR și ce semnifică fiecare?
- Ce rezolvă seturile de instrucțiuni Thumb și Thumb-2?
- Ce rol are Barrel Shifter-ul într-o instrucțiune ARM?
- Numiți cele trei protocoale AMBA și domeniul de utilizare al fiecăruia.
14Direcții de aprofundare2 min
Cu arhitectura procesorului și organizarea memoriei clarificate, cursul următor trece la o constrângere care revine constant în sistemele embedded: consumul de energie. Vom lega direct conceptele de azi (moduri de operare, întreruperi, pipeline) de tehnicile concrete prin care un microcontroler își reduce consumul - sleep, wake-on-interrupt, scalarea frecvenței.
Multe dintre conceptele din acest curs (registre, pipeline, întreruperi) devin tangibile abia în laborator - urmăriți-le concret în laboratoarele disciplinei pe măsură ce lucrați direct pe hardware ARM Cortex-A (Raspberry Pi 5) și Cortex-M/Xtensa (ESP32).