CURSUL 03

Arhitectura Memoriei și Procesoarele ARM

Durată: 120 min de predare Nivel: licență, anul III - recomandat după Cursul 02 Disciplină: Sisteme Încorporate PDF: descarcă suportul EN English version

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.

Recapitulare din cursul anterior
  • 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

Arhitectura von Neumann
Model în care instrucțiunile programului și datele sunt păstrate în aceeași memorie și accesate printr-un mecanism comun de adresare. Originea: raportul lui John von Neumann din 1945, pentru proiectul EDVAC - ideea de „program memorat".
CPU control · ALU · registre Memorie unificată instrucțiuni + date, același spațiu o singură magistrală (concurență instrucțiuni / date) CPU control · ALU · registre Memorie program Memorie date
Fig. 1 - Von Neumann (sus): o magistrală comună, deci instrucțiunile și datele concurează pentru același acces. Harvard (jos, anticipare din secțiunea următoare): căi separate, acces simultan posibil.

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ă.

Von Neumann bottleneck Folosirea aceleiași căi pentru instrucțiuni și date înseamnă că procesorul nu poate prelua o instrucțiune nouă și, în același timp, citi/scrie un operand prin aceeași interfață. În sens modern, „blocajul von Neumann" nu se referă doar la o magistrală fizică unică, ci la diferența tot mai mare dintre viteza procesorului și viteza cu care memoria îi poate livra date. Cache-urile, preluarea anticipată și transferurile în rafală atenuează problema, fără s-o elimine complet.
Exemplu

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

Arhitectura Harvard
Model în care instrucțiunile și datele sunt păstrate în memorii distincte și transferate prin căi separate - eventual cu spații de adrese, lățimi de cuvânt și tehnologii diferite pentru fiecare.

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.

Exemplu - și limitarea ei

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.

Atenție la coerența I-cache / D-cache

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 NeumannHarvardHarvard modificată
Organizarea memorieicomunădistincteseparare doar la anumite niveluri
Acces concurentlimitatsimultansimultan prin I-cache/D-cache
Spații de adreseunificatseparateunificat, cu căi separate local
Flexibilitateridicatămai redusăridicată, hardware mai complex
Utilizări reprezentativemodel conceptual clasicDSP-uri, microcontrolere strictemajoritatea procesoarelor moderne
De reținut Etichetarea unui procesor drept „von Neumann" sau „Harvard" poate ascunde detalii importante: un procesor poate prezenta software-ului un spațiu de adrese unic, dar folosi intern cache-uri separate și magistrale multiple. Pentru sistemele embedded, alegerea influențează timpul de răspuns, consumul energetic, complexitatea software-ului și posibilitatea de actualizare a firmware-ului - exact firele pe care le-am discutat în Cursul 01.

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".

Modelul de licențiere

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":

ProfilDomeniu principalGestiunea memorieiSistem de operareExemple
Cortex-A (Application)sisteme cu SO complexMMU, memorie virtuală, cache avansatLinux, Android, Windowstelefoane, routere, servere
Cortex-R (Real-time)control critic, deterministMPU, memorii TCM predictibileRTOS sau dedicatautomotive, stocare, industrial
Cortex-M (Microcontroller)microcontrolere embeddedMPU opțională, fără MMU clasicăbare-metal sau RTOSIoT, senzori, controlere
Potriviți profilul ARM cu aplicația care i se potrivește cel mai bine

Î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

Ierarhia de memorie: cost energetic per acces

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

RegistruRol
R0-R3parametri de funcție și valori de retur
R4-R11variabile locale, conservate între apeluri de funcții
R12registru 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
Exemplu - apel și revenire dintr-o funcție
arm_call.s
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:

arm_nested_call.s
functie:
  PUSH {R4, LR}
  MOV  R4, R0
  BL   alta_functie
  ADD  R0, R0, R4
  POP  {R4, PC}    ; încărcarea direct în PC realizează revenirea

Particularităț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.

Instr. 1 Fetch Decode Execute Instr. 2 Fetch Decode Execute Instr. 3 Fetch Decode Execute Instr. 4 Fetch Decode Execute
Fig. 2 - Un pipeline de trei etape: după „umplere", câte o instrucțiune se finalizează la fiecare ciclu, deși fiecare instrucțiune individuală traversează tot pipeline-ul.
Accelerarea data de pipeline si costul hazardurilor
Prețul unui salt Când procesorul execută un salt condiționat, instrucțiunile deja aflate în Fetch și Decode (pe traseul „greșit") trebuie eliminate, iar pipeline-ul trebuie „reumplut" de la noua adresă - o penalizare directă de performanță. Procesoarele performante folosesc predicția salturilor pentru a reduce acest cost; microcontrolerele simple, cu pipeline scurt, îl acceptă în schimbul unei implementări mai simple și mai predictibile.

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

IndicatorSemnificație
Nrezultatul are bitul de semn activ (negativ)
Zrezultatul operației este zero
Coperația a produs transport (carry) sau împrumut
Voperația cu semn a produs depășire aritmetică (overflow)
Exemplu - actualizarea și citirea indicatorilor
cpsr_flags.s
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.

De ce contează diferența Un program scris pentru Cortex-M nu trebuie să presupună existența modurilor IRQ/FIQ sau a registrului CPSR clasic, chiar dacă apar frecvent în materiale despre „arhitectura ARM" în general. Verificați întotdeauna dacă documentația se referă la profilul A/R clasic sau la Cortex-M.

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.

Analogie Polling e ca și cum ați verifica la fiecare 5 secunde dacă a sosit un email. O întrerupere e ca o notificare: continuați ce făceați, și sunteți anunțat exact când contează. Diferența de eficiență e enormă, mai ales pe un sistem alimentat pe baterie care poate „adormi" între întreruperi.
Tratarea unei exceptii pe ARM Cortex-M: puneti pasii in ordine

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.

cond_exec.s
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.

Exemplu - indexarea unui tablou într-o singură instrucțiune
barrel_shifter.s
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țieNume completComportament
LSLLogical Shift Leftdeplasare logică stânga - echivalent × 2ⁿ
LSRLogical Shift Rightdeplasare logică dreapta, introduce zerouri
ASRArithmetic Shift Rightpăstrează bitul de semn - împărțire aproximativă la 2ⁿ
RORRotate Rightrotaț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.

Von Neumann bottleneck
limitarea de debit dintr-o magistrală comună program/date.
I-cache / D-cache
cache-uri separate pentru instrucțiuni, respectiv date.
Cortex-A/R/M
profilurile ARM pentru aplicații, timp real, microcontrolere.
SP, LR, PC
Stack Pointer, Link Register, Program Counter (R13-R15).
MSP / PSP
Main/Process Stack Pointer - cele două stive din Cortex-M.
CPSR / xPSR
registre de stare - AArch32 clasic, respectiv Cortex-M.
Barrel Shifter
bloc hardware pentru deplasare/rotație combinată cu ALU.
Thumb / Thumb-2
seturi de instrucțiuni compacte, pe 16 și 16+32 biți.
AMBA (AXI/AHB/APB)
familie de protocoale de interconectare pe cip.

13Întrebări de verificare10 min

  1. Care este diferența fundamentală dintre arhitecturile von Neumann și Harvard?
  2. Ce este arhitectura Harvard modificată și de ce e cea mai des întâlnită azi?
  3. Care sunt cele trei profiluri arhitecturale ARM și pentru ce e optimizat fiecare?
  4. Care este rolul registrelor SP, LR și PC în modelul AArch32?
  5. Ce sunt MSP și PSP în Cortex-M și de ce există două stive?
  6. Cum funcționează un pipeline de trei etape și ce se întâmplă la un salt condiționat?
  7. Ce indicatori conțin registrele CPSR/xPSR și ce semnifică fiecare?
  8. Ce rezolvă seturile de instrucțiuni Thumb și Thumb-2?
  9. Ce rol are Barrel Shifter-ul într-o instrucțiune ARM?
  10. 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).