Table of Contents
Fondazione di elaborazione-periferica Comunicazione
Ad un software che scrive un codice di alto livello, la lettura da un indirizzo di memoria o la scrittura a una variabile è un'operazione atomica semplice. Tuttavia, questa semplicità maschera un sofisticato meccanismo hardware che è fondamentale per tutti i moderni calcoli. La capacità di un processore di controllare un disco rigido, visualizzare un'immagine su uno schermo, o ricevere un pacchetto da una scheda di rete dipende interamente dal rapporto intricato tra due concetti principali: [FLTIO: 0]
La microarchitettura dei registri della CPU
I registri rappresentano il livello più alto di memoria nella gerarchia di archiviazione, che si trova direttamente all'interno del nucleo della CPU. Sono la memoria di lavoro del processore, tenendo i dati immediati, gli indirizzi e le informazioni di controllo necessarie per l'esecuzione delle istruzioni.
General-Purpose Registrazioni e Percorsi di Esecuzione
Il gruppo più visibile dei registri a un programmatore di assemblaggio è il Registro Generale-Purpose (GPRs). In architetture come ARM64 (AArch64), il programmatore ha accesso a 31 registri generali (X0-X30). Questi registri sono la fonte esclusiva e la destinazione delle operazioni di accoppiamento aritmetico (ALU) . Quando il processore esegue un'istruzione come registra i valori
Registrazioni Speciali e Controllo di Sistema
Oltre ai GPR, un processore si affida a una suite di registri speciali per mantenere lo stato e gestire il flusso di esecuzione, spesso invisibili al codice a livello di applicazione, ma costantemente accessibili dal sistema operativo e dal firmware.
- Contenitore di programma (PC): Questo registro contiene l'indirizzo di memoria dell'istruzione attualmente in esecuzione.
- Stack Pointer (SP):] Usato per gestire lo stack delle chiamate, contenente l'indirizzo della parte superiore del frame stack corrente.
- Status Register (PSR / FLAGS):[] memorizza i codici di stato derivanti dalle operazioni ALU, come zero, trasportare, overflow e negativo. Queste bandiere controllano le istruzioni di ramo condizionale e sono essenziali per l'attuazione di loop e dichiarazioni.
- Link Register (LR) / X30:[] Nelle architetture ARM, questo GPR speciale detiene l'indirizzo di ritorno per una chiamata di funzione, consentendo un'invocazione subroutina efficiente senza dover spingere immediatamente l'indirizzo di ritorno sullo stack.
Gestione registro moderna: Rinominazione e Speculazione
In moderni processori fuori ordine, il file di registro fisico è significativamente più grande del registro architettonico impostato dall'architettura set di istruzioni (ISA). La CPU utilizza una tecnica chiamata registrare il rinominamento per superare i rischi di dati. Ad esempio, se un compilatore utilizza il registro architettonico X0 per i valori multipli non correlati, l'hardware mappa questi riferimenti logici ai registri fisici unici.
I Fondamenti di I/O Memoria-Mapped (MMIO)
L'I/O Memory-mapped è una metodologia hardware in cui vengono assegnati i registri di controllo e dati dei dispositivi periferici all'interno della mappa standard del processore. Invece di utilizzare le istruzioni I/O dedicate (come nell'architettura x86 IN/OUT), MMIO consente alla CPU di interagire con i dispositivi utilizzando le istruzioni di carico standard (LDR) e di memorizzare (STR).
L'architettura dello spazio di indirizzo unificato
In un sistema MMIO, lo spazio di indirizzo fisico è condiviso tra RAM di sistema, ROM/flash e registri periferici. Una specifica gamma di indirizzi è riservata ai registri dei dispositivi. Quando la CPU emette un carico o memorizza istruzioni ad un indirizzo all'interno di questo intervallo riservato, il bus di memoria decodifica l'indirizzo e indirizza la transazione all'autobus periferica appropriato (come AMBA AXI o PCI Express) piuttosto che al controller di memoria.
Per esempio, su un tipico microcontrollore ARM Cortex-M, la mappa della memoria è rigorosamente applicata: gli indirizzi da [ a sono per codice, [] a per SRAM, e ] a ] sono riservate esclusivamente caratteristiche di accesso rigoroso per le periferiche.
Confronto MMIO e Port-Mapped I/O (PMIO)
L'alternativa a MMIO è isolata I/O, o I/O mappato a porta (PMIO), storicamente utilizzata dall'architettura x86. PMIO utilizza perni hardware dedicati e istruzioni speciali (IN/OUT) per accedere a uno spazio di indirizzo I/O separato. Entrambi i metodi hanno distinti trade-off di progettazione.
- MMIO Vantaggi:[] Riutilizza la piena potenza del set di istruzioni di memoria della CPU. È possibile utilizzare il dereferencing puntatore in C/C++, applicare operazioni bit-field e sfruttare tutte le modalità di indirizzamento. MMIO non richiede meccanismi speciali di protezione I/O oltre l'unità di gestione della memoria esistente (MMU).
- PMIO Vantaggi:[[] Non consuma spazi di indirizzo preziosi dalla mappa di memoria. Lo spazio dedicato I/O fornisce una separazione pulita tra la memoria dei dati e i registri di controllo, che possono semplificare la progettazione hardware in alcuni sistemi legacy. Tuttavia, I/O basati su porta ha generalmente un throughput inferiore e non può essere utilizzato per i trasferimenti di memoria-burst.
I moderni sistemi x86 utilizzano ancora PMIO per la compatibilità con i dispositivi legacy (ad esempio, il controller di tastiera PS/2 legacy), ma dispositivi ad alte prestazioni come GPU e SSD NVMe si affidano esclusivamente a MMIO tramite il bus PCI Express.
Accedere al dispositivo Registra dal codice ad alta velocità
Quando si scrive un driver di dispositivo in C o C++, l'accesso ai registri MMIO richiede una semantica specifica per evitare che le ottimizzazioni dei compilatori si rompano l'interazione hardware. La parola chiave è essenziale.
La Confluenza dei Registri e MMIO
Il vero "interplay" si verifica ogni volta che un programma deve inviare i dati a una periferica o ricevere i dati da esso. Il processo comporta la movimentazione dei dati tra i registri della CPU e i registri del dispositivo MMIO utilizzando istruzioni di carico/store, ma le implicazioni hardware e del protocollo sono uniche.
Carica/Store Semantics sulla memoria del dispositivo
L'esecuzione di un'istruzione come , dove X1 contiene l'indirizzo del registro di dati di trasmissione di un dispositivo, innesca una sequenza specifica. Il valore del registro generale della CPU (W0) viene posto sul bus di dati. Il tessuto dell'autobus decodifica l'indirizzo di destinazione e lo identifica come una regione di MMIO.
Inquinamento, Interruzioni e Registrazione Bandiere di stato
Il modello di interazione più semplice è il polling. La CPU legge un registro di stato del dispositivo (un indirizzo MMIO) in un GPR, controlla un bit specifico utilizzando un bitmask, e loop fino a quando l'hardware imposta la bandiera indica i dati è pronto. Questa è la forma più semplice di interplay ma rifiuti i cicli della CPU. Il modello di registro interrotto è molto più efficiente. Quando un dispositivo ha i dati di lettura, afferma una linea di stato di errore.
Accesso diretto alla memoria (DMA) e Coordinamento Registro
Per dispositivi ad alta larghezza di banda come schede di rete o controller di archiviazione, il trasferimento dei dati attraverso i GPR della CPU è proibitivamente lento. Direct Memory Access (DMA) risolve questo consentendo alla periferica di trasferire i dati direttamente alla RAM di sistema senza coinvolgere la CPU per ogni parola. Tuttavia, DMA si basa ancora pesantemente sui registri della CPU e MMIO per la sua configurazione.
- La CPU scrive ai registri MMIO del controller DMA per impostare l'indirizzo sorgente, l'indirizzo di destinazione e la lunghezza di trasferimento.
- La CPU scrive a un registro MMIO "start" separato per avviare il trasferimento.
- Mentre il DMA è in corso, la CPU è libera di eseguire altri codici.
- Dopo il trasferimento, il controller DMA scrive al proprio stato registra e solleva un interruzione. La CPU deve quindi leggere questi registri per verificare che la transazione abbia avuto successo.
Questo handshake, dove i registri della CPU configurano il sistema, i motori DMA eseguono lo stato del rapporto di sollevamento pesante e MMIO registra, è la spina dorsale di I/O ad alte prestazioni.
Considerazioni avanzate nelle implementazioni moderne
Con l'aumento della complessità del sistema, sono emersi diversi elementi sofisticati per gestire le peculiarità di MMIO e la sua interazione con lo stato del registro della CPU.
Coerenza di cache e memoria
I registri dei dispositivi sono intrinsecamente non-ipotetici; la lettura di un registro potrebbe cancellare una bandiera di blocco, e la scrittura di un registro potrebbe avviare un motore. Pertanto, le regioni di MMIO sono quasi sempre contrassegnate come Uncacheable o Device-nGnRnE nelle tabelle di pagina di accesso MMU.
MMIO in PCI Express
Lo standard PCI Express (PCIe) è l'interconnessione ad alta velocità dominante in PC, server e sistemi incorporati. I dispositivi PCIe espongono i loro registri di controllo tramite MMIO. Durante l'avvio del sistema, il firmware o il sistema operativo esegue la scansione dell'autobus PCIe e assegna le regioni di memoria a ciascun dispositivo di riferimento (barre).
Sfide di virtualizzazione e IOMMU
In ambienti virtualizzati, un sistema operativo guest non può essere dato accesso fisico diretto ai registri MMIO del dispositivo, in quanto questo romperebbe l'isolamento. L'ipervisor deve intrappolare ed emulare gli accessi MMIO guest, che è lento.
Applicazioni pratiche dei registri e MMIO
Capire questi concetti non è solo accademico, ogni driver periferico scritto per Linux, Windows o un RTOS è costruito su questa fondazione.
Ricevitore/trasmettitore asincrono universale (UART)
Per trasmettere un carattere, un driver deve invocare un registro di stato (MMIO) per verificare se il registro di trasmissione (THR) è vuoto. Legge questo valore in un GPR, testa il bit e loop. Una volta che il THR registra, il driver scrive il carattere all'indirizzo THR (MMIO).
Unità di elaborazione grafica (GPU)
GPU sono processori paralleli che si affidano fortemente a MMIO. La CPU interagisce con il driver GPU attraverso un buffer di anelli di comando e un insieme di registri MMIO. Per inviare il lavoro, la CPU scrive comandi in un buffer di anelli nella memoria di sistema. Poi, scrive a uno specifico registro MMIO "doorbell" sulla GPU. Questo registro porta segnala la GPU che i nuovi comandi stanno aspettando.
Controller di interfaccia di rete (NICs)
I moderni NIC utilizzano un principio simile: hanno un insieme di registri MMIO per il controllo e un insieme di anelli di descrittore nella memoria principale. Quando arriva un pacchetto, il NIC utilizza DMA per posizionare i dati dei pacchetti in un buffer di memoria preallocato e scrive il descrittore buffer nell'anello.
Valutazione di I/O Memoria mappata
Mentre MMIO è il paradigma dominante per le periferiche moderne, è un trade-off di design con pro e contro distinti.
Vantaggi in Progettazione di sistema
MMIO semplifica il modello di programmazione eliminando un set di istruzioni I/O separato, consente una facile integrazione con l'unità di protezione della memoria della CPU (MMU) e consente l'uso di codice C standard per lo sviluppo del driver.
Potenziali svantaggi e cadute
Un altro inconveniente significativo è il consumo di spazio di indirizzo fisico. Su sistemi a 32 bit, dedicare una vasta gamma di spazio di indirizzo a dispositivi non utilizzati o lenti può frammentare la mappa di memoria. Inoltre, l'accesso MMIO è intrinsecamente sequenziale e incacheable, rendendo più lento che accedere ai dati atomici della cache. Un bug comune nello sviluppo del driver manca la parola chiave [IO 12], che causa le ottimizzazioni del compilatore di accesso a un singolo errore di scrittura è l'accesso a rottura di accesso di MM.
Il rapporto simbionico in Architettura di sistema
L'interazione tra i registri della CPU e le barriere di memoria mappate è la simpatia meccanica che guida tutti i computer. I registri forniscono la velocità di blister e la manipolazione immediata dei dati richiesti dal processore, mentre MMIO fornisce l'interfaccia standardizzata e flessibile necessaria per interagire con il mondo fisico delle periferiche. Se uno sviluppatore sta scrivendo un semplice a un UART, inizializzando un complesso processo GPU, o implementando un server di base virtualizzata.