I/O e periferiche: interfacce, polling, interrupt e DMA | Sistemi e Reti Anno 3 Modulo 1 Lezione 08 | Prof. Giagnotti
Sistemi e Reti · Anno 3 · Modulo 1 · Lezione 08
✍ Autore: profgiagnotti · Materia: Sistemi e Reti

I/O e periferiche: dal bus al mondo esterno

CPU e RAM da sole non parlano con nessuno. Scopriamo l'unità di I/O: il ponte che traduce, sincronizza e coordina tastiere, dischi, GPU e rete con il bus di sistema.

⏱ 55 min 📚 Anno 3 🧠 I/O Interface 💻 Polling · Interrupt · DMA
// OBIETTIVI DI APPRENDIMENTO
✓Comprendere il ruolo dell'unità di I/O come ponte tra sistema di elaborazione e ambiente esterno.
✓Distinguere tra periferiche di input, output e memorizzazione, interne ed esterne.
✓Spiegare il funzionamento delle interfacce di I/O: registri di dato, stato, controllo, buffer e indirizzamento.
✓Conoscere le tre modalità di comunicazione: polling, interrupt e DMA, con vantaggi e limiti.
✓Differenziare tra I/O memory-mapped e I/O isolato, valutando quando conviene ciascuno.

1. L'unità di I/O — il confine tra CPU e mondo esterno

CPU e memoria centrale, da sole, non possono fare nulla di utile: hanno bisogno di ricevere dati dall'esterno e di restituire risultati. L'unità di Input/Output è il sottosistema che rende possibile questa comunicazione — è il confine fisico e logico tra il sistema di elaborazione e l'ambiente esterno.

📌 Definizione da ricordare

Unità di I/O: sottosistema che gestisce traduzione dei segnali, sincronizzazione delle velocità, coordinamento dei trasferimenti e indirizzamento delle periferiche tra bus di sistema e mondo esterno.

01 · TRADUZIONE

Traduzione dei segnali

Converte il formato elettrico/logico della periferica nel formato del bus di sistema e viceversa. Una tastiera manda scan code, il bus vuole byte su data bus.

02 · SINCRONIZZAZIONE

Sincronizzazione velocità

La CPU opera a GHz, una tastiera a pochi byte/s, un HDD a MB/s. L'I/O colma il divario con buffer e logiche di attesa.

03 · TRASFERIMENTO

Gestione trasferimenti

Coordina quando e come i dati si spostano tra periferica, bus e memoria: chi inizia, quanto dura, come si segnala la fine.

04 · INDIRIZZAMENTO

Indirizzamento periferiche

Ogni dispositivo ha un indirizzo logico unico per essere identificato dalla CPU, come un numero di casa sul bus.

Senza I/O, la CPU non saprebbe come parlare con una tastiera, un disco o una scheda di rete — dispositivi con velocità, protocolli e formati completamente diversi tra loro e dal bus di sistema.

💬 Tip del docente

All'interrogazione chiedono sempre: "perché non colleghiamo direttamente la periferica al bus?". Risposta in 10 secondi: perché è troppo lenta e parla un linguaggio diverso. Ripeti questa frase e poi aggiungi le 4 funzioni: traduzione, sincronizzazione, trasferimento, indirizzamento.

CPU GHz - veloce RAM memoria centrale BUS dati/stato/ctrl UNITÀ di I/O + Interfacce Registri: DATO | STATO | CTRL Buffer per sincronizzare Traduzione + indirizzamento Polling / Interrupt / DMA memory-mapped vs isolato ⌨️ INPUTtastiera, mouse, sensori 🖥️ OUTPUTmonitor, stampante, attuatori 💾 STORAGESSD, HDD, USB

2. Le interfacce di I/O — il modulo intermedio indispensabile

Una periferica non può essere collegata direttamente al bus di sistema. Perché? Tre motivi fondamentali: è troppo lenta, usa livelli elettrici diversi, parla un protocollo proprietario. L'interfaccia di I/O (detta anche controller o modulo di I/O) fa da adattatore universale.

📌 Definizione da ricordare

Interfaccia di I/O: dispositivo hardware che collega la periferica al bus; espone alla CPU registri standard e gestisce lato periferica il protocollo specifico.

PROBLEMA 1

Velocità diverse

CPU GHz vs tastiera 10 B/s. L'interfaccia inserisce un buffer elastico: la CPU scrive e se ne va, la periferica svuota con calma.

PROBLEMA 2

Formato diverso

Il bus usa 32/64 bit paralleli, la periferica magari seriale. L'interfaccia fa conversione parallelo/seriale e codifica.

PROBLEMA 3

Protocollo diverso

Ogni periferica ha comandi propri. L'interfaccia traduce comandi standard (READ/WRITE) in comandi specifici dell'hardware.

🎯 Esempio in classe

Controller SATA del nostro SSD NVMe: lato bus parla PCIe 4x a 8 GB/s, lato periferica gestisce comandi NVMe (queue, TRIM). Stesso ruolo per la scheda video: lato bus PCIe, lato periferica HDMI/DisplayPort con segnali video TMDS. Senza controller dovremmo riprogettare la CPU per ogni monitor!

3. I registri e il buffer: come parla la CPU con l'interfaccia

La CPU non vede la periferica, vede solo tre tipi di registri nell'interfaccia, mappati su indirizzi.

RegistroCosa contieneDirezioneEsempio
DATO (Data)Il byte/parola in transitoCPU ↔ Interfaccia ↔ PerifericaCarattere digitato, pixel da visualizzare
STATO (Status)Flag: pronta? occupata? errore?Periferica → CPU (sola lettura)Bit READY=1 = dati disponibili
CONTROLLO (Control)Comandi dalla CPUCPU → Periferica (sola scrittura)START, STOP, RESET, INT_ENABLE
💬 Tip del docente

Memorizza con la frase "DSC - Dato Stato Controllo". All'esame disegna sempre tre quadratini etichettati. Se non menzioni il registro di stato, l'interrogazione è insufficiente: è lui che dice alla CPU se può leggere/scrivere.

Il buffer è la chiave per la sincronizzazione: piccola memoria FIFO (First In First Out) dentro l'interfaccia. La CPU deposita velocemente 4KB nel buffer della stampante e torna a eseguire codice, mentre la periferica li stampa in 2 secondi. Senza buffer, la CPU dovrebbe aspettare fisicamente la periferica → spreco enorme.

CPUlegge/scriveregistri I/O INTERFACCIA DI I/O (Controller) DATObyte in transito STATOREADY/BUSY/ERR CTRLSTART/STOP BUFFER FIFOcompensa GHz vs byte/s - CPU libera subito Perifericaprotocollo propriolenta, seriale, specificaEs: tastiera / SSD
C / Pseudocodice · accesso a registri
// La CPU NON parla con la tastiera, parla con i suoi registri mappati // Indirizzi di esempio (memory-mapped) #define DATA_REG 0x40001000 // registro dato #define STATUS_REG 0x40001004 // registro stato: bit0=READY #define CTRL_REG 0x40001008 // registro controllo // Lettura carattere da tastiera (polling - semplificato) while( (*(volatile int*)STATUS_REG & 0x1) == 0 ) { // aspetta che READY diventi 1 } char c = *(volatile char*)DATA_REG; // preleva dato *(volatile int*)CTRL_REG = 0x1; // ACK + riabilita interrupt

4. Indirizzamento: memory-mapped vs I/O isolato

Come assegna la CPU un indirizzo a una periferica? Ci sono due scuole di pensiero, entrambe presenti nei processori che usi.

CaratteristicaMemory-Mapped I/O (MMIO)I/O Isolato / Port-Mapped (x86)
Spazio indirizziUnico: RAM e periferiche condividono lo stesso spazio (es. 0x4000... riservato a I/O)Doppio: spazio RAM separato dallo spazio porte I/O (0-65535)
IstruzioniStesse di memoria: LOAD, STORE, MOVIstruzioni dedicate: IN, OUT (x86)
ProtezioneSi usa MMU / paging come per la RAMServe meccanismo separato, meno flessibile
DecodificaSemplice, meno hardwarePiù complessa, due decodifiche
Dove si usaARM, RISC-V, moderni SoC, GPU, microcontrollorix86 Intel storico, ancora presente per compatibilità
🎯 Esempio in classe

Su Arduino (AVR è memory-mapped) scrivi PORTB = 0xFF per accendere i LED: stai scrivendo in una locazione RAM che è in realtà il registro dato del controller. Su PC x86, per leggere il CMOS clock, il sistema operativo usa out 0x70, al / in al, 0x71: sta usando porte I/O isolate, non MOV. Due mondi, stesso concetto.

🚫 Da non confondere

Memory-mapped NON significa che la periferica è in RAM! Significa solo che condivide lo stesso spazio numerico degli indirizzi. Parte di quegli indirizzi, quando li usi, invece di andare in RAM vanno dirottati sull'interfaccia I/O. È un trucco di numerazione, non fisico.

Assembly x86 · I/O isolato vs MMIO
; ---- I/O ISOLATO (x86, istruzioni speciali) ---- ; Leggo stato tastiera dalla porta 0x64 IN AL, 0x64 ; AL = STATUS_REG porta 64h TEST AL, 1 JZ aspetta ; se READY=0, ripeti IN AL, 0x60 ; AL = DATA_REG porta 60h (tasto) ; ---- MEMORY-MAPPED (ARM / RISC-V, istruzioni normali) ---- LDR R0, =0x40001004 ; R0 = indirizzo STATUS LDR R1, [R0] ; R1 = *STATUS (come una normale variabile) TST R1, #1 BEQ wait LDR R0, =0x40001000 LDRB R2, [R0] ; R2 = carattere da tastiera

5. Le 3 modalità di trasferimento: polling, interrupt e DMA

Una volta mappata l'interfaccia, come fa la CPU a sapere quando trasferire? Tre strategie, in ordine di efficienza crescente.

5.1 Polling (attesa attiva)

La CPU interroga in loop il registro di stato: "Sei pronta? E ora? E ora?". Semplicissimo, ma brucia cicli CPU anche se la periferica risponde dopo 10 ms.

🎯 Quando si usa

Per periferiche velocissime dove l'attesa è brevissima (es. sensore interno) o nei bootloader dove gli interrupt non sono ancora configurati. In Arduino while(!Serial.available()) è polling.

5.2 Interrupt (interruzione)

La CPU si fa gli affari suoi ed esegue altro codice. Quando la periferica è pronta, alza una linea di interrupt, la CPU salva contesto (PC, registri, flag), salta a una ISR - Interrupt Service Routine tramite vettore di interrupt, serve la periferica e riprende da dove aveva lasciato.

📌 Definizione da ricordare

Interrupt: segnale asincrono dalla periferica che sospende il programma corrente, salva il contesto, esegue la ISR e ripristina. La CPU non spreca attese.

POLLING CPU: READY? → NO CPU: READY? → NO CPU: READY? → SI → leggi ❌ Spreco CPU in attesa attiva Semplice, ma inefficiente INTERRUPT CPU fa altro → lavora Periferica → IRQ! CPU salva contesto → ISR → ripresa ✓ CPU libera, evento guidato Ideale per input lento (tastiera) DMA CPU: "DMA, trasferisci 4KB da disco a 0x2000" DMA → bus → RAM diretto Periferica → RAM senza CPU Solo 1 interrupt finale "fatto" 🏆 Blocchi grandi: disco, GPU, rete

5.3 DMA - Direct Memory Access

Per trasferimenti di grandi blocchi (disco → RAM, RAM → scheda video), coinvolgere la CPU byte per byte è insensato. Entra il controller DMA: la CPU gli dice "trasferisci N byte da indirizzo periferica P a indirizzo RAM R" e lo lascia lavorare prendendo il controllo del bus. Il DMA trasferisce tutto direttamente, senza passare per la CPU, e alla fine genera un solo interrupt di completamento.

💬 Tip del docente

Schema da disegnare in verifica: CPU → programma DMA (sorgente, destinazione, contatore) → DMA prende bus (bus request / bus grant) → trasferimento periferica ↔ RAM → interrupt finale → CPU riprende. Se scrivi solo "il DMA va più veloce", prendi mezzo voto. Devi menzionare il bus grant e l'unico interrupt finale.

ModalitàCosto CPULatenzaUso tipico
Polling100% in attesaBassissima se periferica prontaBoot, sensori veloci, debug
InterruptQuasi 0%, solo ISRMedia (salvataggio contesto)Tastiera, mouse, rete a pacchetti
DMASolo setup + 1 interrupt finaleAlta all'inizio, poi throughput maxDisco, SSD, GPU, scheda di rete, audio
⚠️ Errore comune in verifica

Dire che "gli interrupt non usano la CPU". Falso: usano la CPU per eseguire la ISR, ma solo quando serve. Il polling invece la usa sempre per controllare. Il DMA è l'unico che trasferisce veramente senza CPU (a parte il setup).

Pseudocodice · confronto polling vs interrupt
// POLLING - CPU inchiodata char read_polling() { while( (STATUS & READY) == 0 ); // busy waiting! return DATA; } // INTERRUPT - CPU libera, ISR chiamata da HW // main() enable_irq(KEYBOARD_IRQ); while(1) { fai_altro(); // calcoli, altro I/O... } // ISR invocata automaticamente su IRQ void ISR_keyboard() { char c = DATA; // prendi dato buffer_push(c); ACK_interrupt(); } // DMA - CPU ordina e dimentica void dma_disk_to_ram(int disk_lba, void* ram_addr, int size) { DMA_SRC = disk_lba; DMA_DST = ram_addr; DMA_COUNT = size; DMA_START = 1; // da ora lavora il controller DMA, CPU libera } // ... dopo secondi/millisecondi ... void ISR_dma_done() { // trasferimento completato, 1 solo interrupt printf("4KB copiati senza usare la CPU!\n"); }

6. Classificazione delle periferiche: chi fa cosa

Non tutte le periferiche sono uguali. Classificarle ti aiuta a capire che tipo di interfaccia e modalità ti serve.

INPUT · CPU legge

⌨️ Input

Tastiera, mouse, scanner, microfono, webcam, sensori temperatura. Solo verso CPU. Critico il tempo di risposta, spesso gestito a interrupt.

OUTPUT · CPU scrive

🖥️ Output

Monitor, stampante, casse, proiettore, attuatori (motori, relay, LED). Solo da CPU verso esterno. Spesso con buffer grande.

STORAGE · Bidirezionale

💾 Memorizzazione

HDD, SSD NVMe/SATA, chiavetta USB, scheda SD, nastro. Persistente, bidirezionale, blocchi grandi → regno del DMA.

⌨️ INPUT - Solo lettura ▸ Tastiera, mouse ▸ Scanner, microfono ▸ Webcam, sensori IoT Modalità: interrupt // byte piccoli 🖥️ OUTPUT - Solo scrittura ▸ Monitor, proiettore ▸ Stampante, casse ▸ Attuatori, motori, LED Modalità: buffer + polling/DMA 💾 STORAGE - Bidir + persistente ▸ HDD magnetico, SSD NVMe ▸ Chiavetta USB, SD card ▸ Nastro - backup archivio Modalità: DMA obbligatorio

7. Interne vs esterne: bus dedicati e porte standard

// PERIFERICHE INTERNE

PCIe, SATA, M.2

Collegate direttamente su bus interni ad alta velocità, senza overhead di protocollo esterno. Massima banda, latenza minima. Es: SSD NVMe, GPU dedicata, scheda Wi-Fi interna, RAM. Spesso usano DMA e MMIO.

// PERIFERICHE ESTERNE

USB, HDMI, Thunderbolt, Ethernet

Connesse tramite porte standard universali e hot-plug. Velocità variabile, più overhead ma massima compatibilità. Es: chiavette, monitor, stampanti, hub. USB è il re dell'interfaccia esterna: 1 cavo, alimentazione + dati.

💬 Tip del docente

Domanda trabocchetto: "SSD interno vs chiavetta USB: perché il primo è 10 volte più veloce se entrambi sono Flash?". Risposta: non è la memoria, è il bus. NVMe su PCIe 4x = 7 GB/s, USB 3.0 = 400 MB/s reali. Stessa tecnologia, interfaccia diversa. Ricordalo.

8. Verifica operativa

🔬 Metti alla prova il tuo I/O

  1. Perché una tastiera non può essere collegata direttamente al data bus? Cita almeno 2 motivi.
  2. Disegna e spiega i 3 registri di un'interfaccia: cosa contiene ciascuno e chi lo legge/scrive.
  3. Hai un sensore di temperatura che invia 1 byte ogni 10 secondi. Meglio polling, interrupt o DMA? Motiva.
  4. Devi copiare 2 GB da SSD a RAM. Perché usare DMA invece di interrupt byte-per-byte? Quanti interrupt risparmi?
  5. Differenza pratica: su un microcontrollore ARM scrivi *(0x40001000)= 'A' per mandare una lettera su UART. È memory-mapped o I/O isolato? Perché?
✅ Soluzione ragionata

1) Troppo lenta (GHz vs Hz) e protocollo diverso (scan code vs bus parallelo). Serve buffer e traduzione → interfaccia.
2) DATA = dato in transito (R/W), STATUS = flag READY/BUSY/ERR (R per CPU), CONTROL = START/STOP/INT_ENABLE (W per CPU).
3) Interrupt: dato raro, polling sprecherebbe CPU per 10 s in attesa. DMA eccessivo per 1 byte.
4) Con interrupt: 2GB = 2 miliardi di interrupt + ISR. Con DMA: setup + 1 interrupt finale = 1. Risparmio enorme, bus libero.
5) Memory-mapped: usi istruzione STORE normale su indirizzo che sembra RAM, non IN/OUT. Tipico ARM/RISC-V.

⚠️ Errore comune finale

Confondere buffer con cache. Buffer = nell'interfaccia I/O, compensa velocità periferica vs CPU, FIFO piccola. Cache = tra CPU e RAM, velocizza accessi a RAM. Ruoli diversi, posizioni diverse, anche se entrambi "memorizzano temporaneamente".

✓Unità di I/O = ponte indispensabile: traduzione, sincronizzazione, gestione trasferimenti, indirizzamento.
✓Interfaccia / Controller necessaria perché periferiche troppo lente e con protocolli diversi dal bus.
✓Tre registri standard: DATA (contenuto), STATUS (pronta?), CONTROL (comandi) + buffer FIFO.
✓Memory-mapped: stesso spazio indirizzi, LOAD/STORE. Isolato x86: spazio porte separato, IN/OUT. ARM/RISC-V usano MMIO.
✓Polling = attesa attiva, spreco CPU. Interrupt = CPU libera, ISR su IRQ. DMA = blocco diretto periferica↔RAM, 1 interrupt finale.
✓Periferiche: input (sensori), output (attuatori), storage bidirezionale (SSD/HDD) → DMA.
✓Interne = PCIe/SATA/M.2 ultra veloci. Esterne = USB/HDMI/Ethernet universali hot-plug.

📚 Prossimo passo - Le componenti di un PC e la fase di avvio

Ora che sai come CPU parla con periferiche, apriamo davvero il case: scheda madre, chipset, alimentazione, BIOS/UEFI e la sequenza di boot che carica il sistema operativo usando proprio le modalità I/O appena viste. Porta schema periferiche interne/esterne.