Architettura del computer: von Neumann, CPU, memorie e ciclo macchina
1) «Il computer ha 500 GB di memoria»: la parola che sbaglia da sola
2) Il modello di von Neumann: che cosa c'è davvero nel rapporto del 1945
3) Von Neumann o Harvard: una memoria o due (e perché il tuo PC è tutti e due)
4) Il collo di bottiglia: che cosa disse davvero Backus (e che cosa non disse)
5) Dentro la CPU: unità di controllo, ALU, registri (e i nomi che cambiano fra i libri)
6) Il ciclo macchina passo per passo: la traccia di esecuzione, riga per riga
7) La gerarchia delle memorie: i numeri veri, misurati su processori con un nome
8) I bus e il conto 2ⁿ: quanta memoria posso indirizzare
9) Il clock: perché i gigahertz non misurano la velocità
10) Dodici esercizi svolti passo passo
11) Gli errori che ti costano il voto
12) Domande frequenti
«Il computer ha 500 GB di memoria»: la parola che sbaglia da sola
Partiamo da questa frase perché è sbagliata in un punto solo. Non nel numero: 500 GB è una capacità plausibile. È sbagliata la parola «memoria» — e non è colpa tua, è colpa di come l'italiano ha diviso il mondo.
L'inglese ha due sostantivi diversi: memory per la RAM e storage per il disco. L'italiano ne ha uno. Il vocabolario scolastico prova a rattoppare con due aggettivi, memoria centrale e memoria di massa, ma lascia lo stesso nome a due oggetti che non si somigliano in niente: quindi ti dà due etichette da imparare, non due idee da distinguere. I sistemi operativi, che il problema ce l'hanno addosso tutti i giorni, sono più netti del tuo libro: Android in italiano ha una voce «Memoria» e una voce «Spazio di archiviazione», Windows ha «Memoria» e «Archiviazione». Loro le hanno separate.
Poi c'è il negozio, e quello lavora attivamente contro di te. Il telefono te lo vendono come «8 GB di RAM + 256 GB di ROM». Ma su quei 256 GB tu ci scrivi le foto, quindi di sola lettura non sono per niente, mentre il giorno dopo il libro ti spiega che ROM sta per read only memory e contiene il firmware di avvio. Non stai capendo male: sono due usi diversi della stessa sigla, e uno dei due è marketing. Quando in verifica ti chiedono «la ROM è una memoria di massa?», la risposta giusta è no, e il criterio è questo: la ROM vera è piccola, non riscrivibile dall'utente e non ci si salvano file, mentre una memoria di massa è per definizione riscrivibile e ospita un file system. La ragione per cui hai esitato, invece, è appena stata scritta qui sopra.
I tre numeri che separano davvero RAM e disco
Non è una questione di parole. Sono tre grandezze misurabili, e su tutte e tre la distanza è enorme.Capacità. Una macchina scolastica tipica ha 8 GB di RAM e 500 GB di disco. Attenzione però a come si fa il rapporto, perché è la prima trappola del capitolo: i due numeri non sono scritti nella stessa convenzione. La RAM si vende a potenze di due, quindi «8 GB» sono in realtà 8 GiB; il disco si vende in giga decimali. Si torna sempre ai byte grezzi:
disco 500 GB = 500 x 10^9 B = 500.000.000.000 B RAM 8 GiB = 8 x 2^30 B = 8.589.934.592 B rapporto 500.000.000.000 : 8.589.934.592 = 58,2Circa 58 volte tanto, non 62,5. Il 62,5 esce dal dividere le etichette del negozio l'una per l'altra, cioè facendo esattamente l'errore che questa guida ti insegna a evitare e che la sezione 11 rimette in fila con la regola operativa: massa e rete in decimale, RAM e indirizzamento in binario. Cinquantotto volte resta comunque un abisso: se «la memoria» fosse una cosa sola, non si spiegherebbe perché aprire venti schede del browser rallenta tutto mentre il disco è pieno al 20 per cento.
Persistenza. Una cella di DRAM (dynamic random access memory, memoria dinamica ad accesso casuale) è 1 transistor più 1 condensatore — la sigla che trovi nei testi è 1T1C. Il condensatore perde carica da solo, quindi ogni riga va riletta e riscritta. JEDEC, l'ente che pubblica gli standard delle memorie, fissa la finestra di refresh a 64 ms per le DRAM fino alla DDR4 a temperatura normale: 1 ÷ 0,064 = 15,6 volte al secondo. Il valore non è universale, e vale la pena saperlo perché qui datiamo tutto: sopra gli 85 °C la finestra si dimezza a 32 ms, e la DDR5 adotta i 32 ms anche a temperatura normale. Quello che con lei si è accorciato è l'intervallo fra un comando di refresh e il successivo, non la finestra. Ma l'idea non cambia: una memoria che, per non dimenticare, deve ripetersi una quindicina di volte al secondo quello che sa. Un disco non ha bisogno di niente del genere.
Velocità. Qui i numeri fanno il lavoro da soli. Le righe sono numerate apposta, così i rimandi non ballano:
RAM (DRAM) SSD NVMe disco a piatti
(1) capacita' tipica 8 - 16 GB 0,5 - 2 TB 1 - 4 TB
(2) tempo di accesso ~ 80 ns ~ 50 us ~ 8 ms
(3) lo stesso, in s 0,000 000 08 0,000 05 0,008
(4) quante volte
piu' lenta 1 ~ 625 ~ 100 000
(5) se togli corrente perde tutto ricorda ricorda
Il conto della riga (4) è una divisione: 0,008 s ÷ 0,000 000 08 s = 100.000, e 0,000 05 ÷ 0,000 000 08 = 625. Fra la RAM e un disco a piatti non c'è una differenza di grado, ci sono cinque ordini di grandezza. Quegli 80 ns sono un valore tondo, scelto perché il rapporto si legga a occhio: nella sezione 7 troverai la RAM misurata su processori veri, fra 73 e 100 ns, e con quei valori i due rapporti vengono un po' diversi. È il punto della sezione 7, non una smentita di questa. Quel valore di circa 8 ms lo scomponiamo nella sezione 7, e va detto subito com'è fatto: per metà è aritmetica — mezzo giro di piatto a 7.200 giri al minuto, 4,17 ms, che si calcola in trenta secondi — e per metà è un dato meccanico di targa, il tempo di spostamento della testina, 4-8 ms, che dagli RPM non si ricava.E l'esperimento costa zero. Spegni la macchina senza salvare. Quello che ritrovi era su disco, quello che è sparito era in RAM. Se «la memoria» fosse una sola, il documento non salvato sopravviverebbe.
La riga da tenere. «Memoria» in italiano è un sostantivo che fa due lavori. Ogni volta che lo scrivi in una verifica, aggiungi l'aggettivo: centrale o di massa. Metà degli errori di questo capitolo si fermano lì.
Come leggere questa guida
L'argomento non è un'aggiunta del tuo professore: sta scritto nei programmi, e i riferimenti qui sotto sono stati aperti uno per uno.Negli istituti tecnici è «Architettura e componenti di un computer», voce delle Conoscenze di Tecnologie informatiche al primo biennio, con l'abilità «Riconoscere le caratteristiche funzionali di un computer (calcolo, elaborazione, comunicazione)». Le due frasi stanno nelle Linee guida per il primo biennio, Direttiva MIUR n. 57 del 15 luglio 2010, Allegato A.2 – Settore tecnologico. Il DPR 88/2010 va citato per il quadro orario, ed è il suo Allegato C a dare le 99 ore al primo anno: quel decreto ha solo quattro allegati, A, B, C e D, e un «Allegato A.2 del DPR 88/2010» semplicemente non esiste. Nel secondo biennio di Informatica e Telecomunicazioni l'argomento torna come prima voce delle Conoscenze di Sistemi e reti: «Struttura, architettura e componenti dei sistemi di elaborazione».
Il liceo scientifico opzione scienze applicate ha Informatica per 66 ore in ciascuno dei cinque anni (quadro orario, Allegato F al DPR 89/2010). Le Indicazioni nazionali per quel percorso — che sono un altro decreto, e per una coincidenza scomoda hanno anche loro un Allegato F: Allegato F al DM interministeriale 7 ottobre 2010 n. 211 — sono l'unico documento programmatico dell'informatica scolastica italiana in cui von Neumann compare per nome, e lo fanno così: «gli elementi funzionali della macchina di Von Neumann: CPU, memoria, dischi, bus e le principali periferiche». Nel liceo scientifico ordinario non c'è: dentro Matematica ci sono algoritmo, calcolabilità e rappresentazione dei dati, non l'architettura.
Alle medie non c'era nelle Indicazioni 2012, ed entra con le Nuove Indicazioni (Allegato al DM 9 dicembre 2025 n. 221, in Gazzetta Ufficiale il 27 gennaio 2026) a partire dall'a.s. 2026/27. Fra le competenze attese al termine della classe terza, voce Informatica, il testo chiede di «Comprendere a livello generale l'architettura di principio (fisica e funzionale) di un sistema informatico, le sue principali componenti hardware e software e i meccanismi fondamentali di Internet». Una nota per chi confronta i documenti e trova due versioni diverse: nella bozza del marzo 2025 la stessa frase diceva «di un sistema di elaborazione digitale», e l'espressione è stata cambiata in «sistema informatico» nel testo definitivo. È la versione definitiva quella che fa fede, e quella è la citazione qui sopra. Aggiungo che nelle Nuove Indicazioni von Neumann non è nominato: l'ho cercato nel testo, non c'è.
Un'onestà utile, perché in giro si legge il contrario: l'algebra di Boole non compare fra le conoscenze prescritte in nessuno dei tre documenti appena citati — l'ho cercata in tutti e tre, la parola non c'è. Si insegna dappertutto, ed è un prerequisito didattico reale, ma chi te la vende come obbligo di programma non ha una fonte.
Le sezioni da 1 a 4 e la 9 sono alla portata del primo biennio e del liceo scienze applicate. Le sezioni da 5 a 8 sono livello verifica di terza all'istituto tecnico. Le sezioni 10 e 11, più le domande frequenti in coda, servono la sera prima del compito.
Prerequisiti, che qui non rispieghiamo
Il binario e l'esadecimale stanno nella guida sui sistemi di numerazione: binario, decimale, esadecimale. Le porte AND, OR e NOT stanno in algebra di Boole e porte logiche. I diagrammi di flusso stanno in algoritmi e diagrammi di flusso. Questa guida è il punto in cui quei tre pezzi smettono di stare ognuno per conto suo e diventano una macchina che esegue davvero.Pubblicità
Il modello di von Neumann: che cosa c'è davvero nel rapporto del 1945
Il documento esiste, si può leggere, e quasi nessuno lo apre. Si intitola First Draft of a Report on the EDVAC, porta la data del 30 giugno 1945 e nasce dal contratto W-670-ORD-4926 fra lo United States Army Ordnance Department e la Moore School of Electrical Engineering della University of Pennsylvania. Sul frontespizio c'è un nome solo: John von Neumann.
Le cinque parti, come le elenca il rapporto
La sezione 2.0, MAIN SUBDIVISIONS OF THE SYSTEM, enumera cinque parti, ognuna introdotta da un ordinale.| § | Ordinale nel testo | Sigla | Denominazione originale | Come la chiami tu |
|---|---|---|---|---|
| 2.2 | First | CA | central arithmetical part | ALU, unità aritmetico-logica |
| 2.3 | Second | CC | central control | unità di controllo |
| 2.4-2.5 | Third | M | memory | memoria centrale |
| 2.7 | Fourth | I | input | ingresso |
| 2.8 | Fifth | O | output | uscita |
Sulla memoria vale la pena essere precisi, perché è l'unica delle cinque a stare a cavallo di due paragrafi: l'ordinale «Third» apre il § 2.4, e la frase che la battezza — the third specific part of the device: M — chiude il § 2.5.
Il § 2.6 fa due cose che valgono tutta la sezione. Primo, raggruppa CA e CC sotto un'unica sigla, C: è da lì che nasce la nozione moderna di CPU (central processing unit, unità centrale di elaborazione) — la CPU non è una delle cinque parti del rapporto, è la somma delle prime due. Secondo, introduce R, l'outside recording medium, che invece resta fuori dal conto.
FUORI DAL DISPOSITIVO
------------------------------------------------------------
R outside recording medium (§ 2.6)
schede perforate, nastro magnetico
------------------------------------------------------------
v R --> I ^ O --> R
============================================================ confine
v ^
+--------------------------+ +--------------------------+
I input (§ 2.7) O output (§ 2.8)
+--------------------------+ +--------------------------+
v I --> M ^ M --> O
+-----------------------------------------------------+
M memory (§ 2.5)
+-----------------------------------------------------+
v M --> C ^ C --> M
+-----------------------------------------------------+
C = CC central control (§ 2.3)
CA central arithmetical part (§ 2.2)
+-----------------------------------------------------+
frecce che NON esistono: I --> C C --> O R --> C
Tre precisazioni che i manuali saltano quasi sempre. Due si leggono nello schema, la terza no, e dirlo è più onesto che far finta.R non è una delle cinque parti. L'outside recording medium — schede, nastri — è introdotto nel § 2.6, ma sta fuori dal dispositivo e von Neumann non lo numera. Nello schema è sopra la riga del confine. Chi conta «sei parti», o chi mette R al posto di O, ha letto il riassunto di un riassunto.
I e O parlano con M, non con C. Il § 2.7 dice che è meglio fare tutti i trasferimenti da R verso M, e mai direttamente verso C; il § 2.8 dice la cosa simmetrica in uscita. Nello schema è l'ultima riga: le frecce I → C e C → O sono elencate fra quelle che non esistono.
Il bus non c'è, e questo nello schema non si vede — nessun disegno può mostrare un'assenza. Si verifica sul testo, ed è una verifica che puoi rifare tu: la parola bus nel rapporto non compare mai, e non compare mai nemmeno l'espressione «architettura di von Neumann». Elencare il bus fra le parti del modello è un errore storico: il bus è un'astrazione arrivata dopo, e lo incontrerai nella sezione 8 come concetto tecnico, non come citazione. Stessa storia per la parola «registro»: nel rapporto compare una volta sola, e come verbo. I nomi PC (program counter, il registro che tiene l'indirizzo della prossima istruzione) e IR (instruction register, il registro che tiene l'istruzione in corso), che incontrerai per esteso nella sezione 5, nel 1945 non ci sono. Arrivano dopo.
Una bozza incompiuta, e va detto
Il documento fondativo dell'informatica è un lavoro non finito. Michael D. Godfrey, che ne ha curato l'edizione critica per gli IEEE Annals of the History of Computing — la ristampa è al vol. 15, n. 4, 1993, pp. 27-75, DOI 10.1109/85.238389 — lo scrive nell'introduzione che accompagna quella ristampa, e sono quattro affermazioni sue, non del testo di von Neumann: il dattiloscritto non fu mai riletto; il testo rimanda in continuazione a sezioni mai scritte, e mancano proprio quella sulla programmazione e quella sull'input/output; i rinvii irrisolti riguardano le sezioni successive alla 15.0, dove il testo si ferma; il manoscritto autografo da cui fu battuto è stato cercato e non è mai stato ritrovato. (Un avvertimento se vai a cercarla: Godfrey nella sua stessa introduzione scrive «pp. 27-43», mentre il catalogo dell'editore dà 27-75. Succede, e quando due riferimenti non tornano fa fede l'indice del fascicolo, non la citazione di seconda mano.)E c'è un dettaglio che rimette la cosa nella luce giusta. L'unico riferimento bibliografico dell'intero rapporto non è a un ingegnere: è a due neurofisiologi, W. S. McCulloch e W. Pitts, A logical calculus of the ideas immanent in nervous activity, in Bulletin of Mathematical Biophysics, vol. 5, 1943, pp. 115-133 — e nel dattiloscritto il cognome è storpiato in «MacCulloch», due volte, con perfino l'iniziale sbagliata la seconda volta. La sezione 4.0 si intitola ELEMENTS, SYNCHRONISM NEURON ANALOGY e la 6.0 introduce gli E-elements, elementi ideali modellati sul neurone. L'analogia di von Neumann è con il sistema nervoso, non con una macchina utensile. Quando il tuo libro scrive «la CPU è il cervello del computer», sta ripetendo senza saperlo una metafora vecchia di ottant'anni — che però nel rapporto era un'ipotesi di lavoro sui circuiti, non uno slogan.
E la paternità: il documento che ha fatto perdere il brevetto
È pacifico che il testo l'abbia scritto lui. È contestato che le idee fossero sue.La Moore School ragionava sulla memorizzazione del programma circa sette mesi prima che von Neumann entrasse nel progetto: il 29 gennaio 1944 J. Presper Eckert mette per iscritto la Disclosure of a Magnetic Calculating Machine, che descrive una macchina elettronica capace di tenere programma e dati in memoria elettronica; von Neumann incontra Goldstine alla stazione di Aberdeen nell'estate del 1944 e vede l'ENIAC per la prima volta, con il nulla osta di sicurezza, il 7 settembre 1944. Sette mesi, dunque, non otto. Eckert e John Mauchly sostennero sempre che il concetto fosse emerso dalle riunioni del gruppo.
Fu Herman Goldstine, ufficiale di collegamento dell'Army, a far ciclostilare le note. Ventiquattro copie furono distribuite il 25 giugno 1945 alle persone legate al progetto EDVAC, con il solo nome di von Neumann in copertina; il rapporto porta invece in frontespizio la data del 30 giugno 1945, ed è quella che si cita come data del documento. Le due date convivono e non vanno fuse in una sola: quante copie siano circolate in tutto, poi, resta incerto. Il seguito è agli atti di un tribunale federale:
brevetto ENIAC US 3.120.606 domanda depositata 26 giugno 1947 (Eckert e Mauchly) brevetto concesso 4 febbraio 1964 causa Honeywell v. Sperry Rand giudice Earl R. Larson (distretto del Minnesota) sentenza di annullamento 19 ottobre 1973Attenzione alla data: diverse fonti secondarie riportano il 10 ottobre, ma la decisione è del 19 ottobre 1973. Fra i motivi dell'annullamento, la circolazione del First Draft fu qualificata come pubblicazione ai fini di legge, cioè arte nota più di un anno prima del deposito. In una riga, ed è la frase da portare all'orale: il documento che ha dato a von Neumann il nome dell'architettura è lo stesso che ha fatto perdere il brevetto a Eckert e Mauchly.
Un'ultima nota di terminologia, perché i libri divergono. Troverai «modello di von Neumann», «macchina di von Neumann» e «architettura di von Neumann» usati come sinonimi: lo sono. Nessuna delle tre espressioni compare nel rapporto del 1945.
Von Neumann o Harvard: una memoria o due (e perché il tuo PC è tutti e due)
La differenza che ti insegnano è «una memoria contro due». È vera e insufficiente: si ferma alla prima riga di una tabella che ne ha cinque, e la riga che conta davvero è l'ultima.
| von Neumann | Harvard (pura) | |
|---|---|---|
| Memoria | una sola, condivisa fra istruzioni e dati | due, fisicamente separate |
| Bus verso la memoria | uno solo | due indipendenti |
| Spazio di indirizzamento | unico | distinto: l'indirizzo 0 delle istruzioni non è l'indirizzo 0 dei dati |
| Accesso simultaneo | impossibile: o l'istruzione o il dato | istruzione e dato nello stesso ciclo, anche senza cache |
| Ampiezza delle parole | di fatto vincolata alla cella: un'istruzione più larga costa più accessi | libera su ciascun lato: l'istruzione arriva in un colpo solo |
VON NEUMANN HARVARD (pura)
+-----------------------+ +-----------+ +-----------+
M una sola memoria Flash SRAM
istruzioni E dati istruzioni dati
+-----------------------+ +-----------+ +-----------+
^ v ^ v ^ v
un solo bus bus istruzioni bus dati
^ v ^ v ^ v
+-----------------------+ +--------------------------+
CPU CPU
+-----------------------+ +--------------------------+
in un ciclo passa in un ciclo passano
O l'istruzione O il dato l'istruzione E il dato
L'ultima riga della tabella è quella che rende Harvard utile per davvero, ed è quella che quasi nessun manuale scolastico scrive — ma va detta con precisione, perché nella versione sbrigativa è falsa. Non è vero che «in una memoria unica un'istruzione più larga della cella non si può fare»: si può benissimo, si spalma su più celle consecutive, e la controprova sta nella sezione 8 di questa stessa guida, dove l'8088 legge otto bit per volta ed esegue istruzioni x86 lunghe parecchi byte. Quello che è vero è il costo: ogni prelievo diventa due o tre accessi invece di uno. Con memorie separate, invece, ciascuna ha la larghezza che le serve e l'istruzione arriva in un colpo solo. In un microcontrollore AVR a 8 bit i dati sono a 8 bit e le istruzioni a 16, e ognuna delle due memorie è dimensionata per il suo mestiere.Harvard vera: i microcontrollori
Non è archeologia. I datasheet Microchip/Atmel degli AVR (ATmega32, ATmega128) lo dichiarano in prima pagina: architettura Harvard con memorie e bus separati per programma e dati, con il Flash del programma su un bus di indirizzi distinto da quello della SRAM (static random access memory, memoria statica: niente condensatore da rinfrescare, quindi veloce e cara — è di questa che sono fatte le cache) dei dati.La conseguenza è misurabile e va detta con i numeri. Con un pipelining a un solo livello, mentre un'istruzione viene eseguita la successiva è già stata prelevata: si arriva così a un'istruzione per ciclo di clock. L'AVR ha inoltre 32 registri general purpose — non un accumulatore solo, come nei modelli didattici che userai nella sezione 6. Stesse scelte nei PIC e nei DSP.
È anche l'unico punto in cui i programmi ministeriali nominano esplicitamente questa roba: TPSIT del secondo biennio, articolazione Telecomunicazioni, chiede «Architettura e tecniche di programmazione dei microcontrollori e dei sistemi embedded».
Il nome è un'etichetta appiccicata dopo
Viene dall'Harvard Mark I (1944), che teneva le istruzioni su nastro perforato largo 24 bit e i dati in contatori elettromeccanici. Ma l'espressione «Harvard architecture» fu coniata decenni dopo, nel mondo dei microcontrollori, e applicata all'indietro a una macchina che non l'aveva mai sentita nominare. È esattamente la stessa situazione della sezione 2: «architettura di von Neumann» non è nel rapporto di von Neumann, «architettura Harvard» non è nei documenti dell'Harvard Mark I. Sono due nomi retrospettivi, e sapere che lo sono ti evita di trattarli come definizioni di legge.E il computer su cui stai leggendo?
Né l'una né l'altra. ARM, Power ISA e x86 sono Harvard modificate, e le varianti sono tre.1) Split cache, la più diffusa, ed è quella del tuo PC. C'è un solo spazio di indirizzamento — quindi verso il programmatore il modello resta von Neumann, un indirizzo è un indirizzo e basta — ma la CPU preleva le istruzioni dalla cache istruzioni e i dati dalla cache dati. Sono le due righe L1i e L1d che trovi etichettate così nelle tabelle della sezione 7: il parallelismo Harvard esiste, ma solo ai livelli bassi della gerarchia.
2) Memoria programma leggibile come dati: spazi separati, ma istruzioni speciali permettono di leggere il Flash come se fosse un dato (per le costanti iniziali) o di riscriverlo. È il caso tipico dei microcontrollori.
3) Memoria dati eseguibile come programma: per esempio i Maxim MAXQ, dove si può eseguire da qualunque segmento, ma lo stesso segmento non può essere letto come dato mentre lo si esegue.
Un esempio concreto della prima variante mescolata alla seconda: nei Cortex-M i bus sono separati — bus ICode verso il Flash per le istruzioni, system bus per i dati — ma accedono a un unico spazio di memoria, e un arbitro consente l'accesso alla memoria istruzioni da entrambi i bus, non però nello stesso momento. Separati nei percorsi, uniti nell'indirizzamento, non simultanei.
La frase da portare all'interrogazione. Nessun PC moderno è von Neumann in senso stretto e nessuno è Harvard in senso stretto: è von Neumann verso il programma — spazio di indirizzamento unico — e Harvard verso il silicio — percorsi separati in L1. Chi risponde «il mio PC è di von Neumann» dice una cosa vera al livello di astrazione del programmatore e falsa al livello del progettista, e la parte importante della risposta è dichiarare a quale livello si sta parlando.
Sui nomi, un'ultima avvertenza. Alcuni testi italiani chiamano «architettura Harvard» qualunque macchina con L1i e L1d separate, altri riservano il termine solo agli spazi di indirizzamento distinti e per i PC usano sempre «Harvard modificata». La seconda è più precisa, la prima la incontrerai lo stesso: se in verifica scrivi «Harvard modificata» e spieghi perché, sei coperto in entrambi i casi.Il collo di bottiglia: che cosa disse davvero Backus (e che cosa non disse)
Questa espressione ha un autore, una data, una rivista e una pagina. È raro, in informatica, e conviene approfittarne.
John Backus riceve l'ACM Turing Award del 1977, consegnato alla ACM Annual Conference di Seattle il 17 ottobre. La sua Turing Lecture esce l'anno dopo con il titolo Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs, in Communications of the ACM, vol. 21, n. 8, agosto 1978, pp. 613-641 (DOI 10.1145/359576.359579). Il passaggio che ci interessa apre la sezione 3, Von Neumann Computers, a pagina 615, e l'ho letto sul testo pubblicato.
Lì Backus riduce il calcolatore a tre pezzi soli: una CPU, uno store — la memoria — e un tubo di collegamento capace di trasmettere una sola parola per volta fra i due, oltre a mandare un indirizzo alla memoria. E poi scrive la frase, che nell'originale suona così: «I propose to call this tube the von Neumann bottleneck».
Il ragionamento che i manuali tagliano
Quello che segue è la parte buona, e sta tutta in tre passaggi.Primo. Il compito di un programma è cambiare in modo sostanziale il contenuto della memoria. Ma questo cambiamento deve avvenire pompando singole parole avanti e indietro attraverso quel tubo. Un programma che modifica un milione di celle deve far passare un milione di parole, una alla volta, nello stesso identico condotto.
Secondo, ed è l'osservazione che nessuno riporta. Backus la apre con un avverbio che vale tutto, ironically: gran parte di quel traffico non è dato utile, sono nomi di dati, cioè indirizzi, più le operazioni che servono soltanto a calcolare indirizzi. E c'è un regresso: prima che una parola possa passare nel tubo, il suo indirizzo deve già essere nella CPU. O ci è arrivato dalla memoria — e allora serviva a sua volta un indirizzo — oppure è stato generato dalla CPU con una regola fissa, e l'esempio che fa lui è proprio «aggiungi 1 al program counter».
Terzo, ed è il punto vero. Per Backus non è soltanto un collo di bottiglia fisico per il traffico dei dati: è soprattutto un collo di bottiglia intellettuale, che ci ha tenuti legati al pensiero una parola per volta invece di spingerci a ragionare per unità concettuali più grandi. Programmare, conclude, è in gran parte pianificare e dettagliare il traffico di parole attraverso quel condotto — e buona parte di quel traffico non riguarda i dati, ma dove trovarli. Da qui la proposta dell'articolo, che è la programmazione funzionale.
Il tubo, con i numeri di una singola istruzione
Prendi l'istruzioneADD 201 della macchina didattica che trovi tracciata riga per riga nella sezione 6: somma all'accumulatore il contenuto della cella 201. Ecco che cosa attraversa il tubo, nell'ordine, per una sola istruzione:che cosa passa nel tubo che cos'e' davvero ----------------------------------------- ----------------------- 1. 0x011 CPU -----> memoria un indirizzo (un nome) 2. 0x20C9 memoria -> CPU l'istruzione 3. 0x0C9 CPU -----> memoria un indirizzo (un nome) 4. 0x000A memoria -> CPU IL DATO quattro transiti, una parola per volta, sullo stesso bus dati utili trasportati: 1 su 4Due interrogazioni alla memoria per una sola somma: una per l'istruzione, una per l'operando. E dei quattro passaggi, due sono indirizzi e uno è l'istruzione: un solo transito su quattro porta il numero che stai davvero sommando. È letteralmente l'ironia di Backus, contata a mano.
Ed è anche la ragione per cui l'architettura Harvard della sezione 3 ha senso — ma attenzione a quali transiti si sovrappongono, perché è facile dire la cosa sbagliata. I passaggi 3-4 non possono avvenire in parallelo con i passaggi 1-2 della stessa istruzione: l'indirizzo dell'operando si conosce solo dopo aver ricevuto e decodificato l'istruzione, quindi dipendono l'uno dall'altro. Il parallelismo vero è un altro: con due bus, il prelievo dell'istruzione successiva — i passaggi 1-2 della prossima — può sovrapporsi all'accesso al dato di quella in corso, i passaggi 3-4 di questa. È esattamente il pipelining a un livello dell'AVR visto nella sezione 3. Il collo di bottiglia non sparisce, si sdoppia.
L'errore da non commettere, ed è comodissimo da fare
Backus non stava parlando della lentezza della RAM rispetto alla CPU.Quel problema esiste, ha un nome — memory wall — e nasce dagli anni Novanta in poi, quando la frequenza dei processori cresce molto più in fretta dei tempi di accesso della DRAM. Nel 1977 il divario di velocità era modesto, e la cache non era l'oggetto centrale che è oggi. Backus stava facendo un'argomentazione sul linguaggio e sul modello di pensiero, non una misura di latenza: attribuirgli il memory wall è un anacronismo di quindici anni buoni.
Perché te lo dico invece di lasciar perdere. Perché la confusione è comoda: «collo di bottiglia = la RAM è lenta» è una frase che funziona, si ricorda e in un tema di sistemi sembra giusta. E infatti circola dappertutto. Se in verifica ti chiedono che cos'è il collo di bottiglia di von Neumann, la risposta completa ha due tempi: il limite strutturale è il bus unico condiviso fra istruzioni e dati, e il termine lo conia Backus nel 1978 parlando di modelli di programmazione; la lentezza della memoria rispetto al processore è un altro problema, si chiama memory wall, e la risposta dell'industria a quello è la gerarchia delle cache della sezione 7.
Le due cose si toccano, però, ed è giusto dirlo: quando la RAM diventa cento volte più lenta della CPU, il tubo di Backus smette di essere solo un limite concettuale e diventa anche un limite di prestazioni misurabile. Il conto lo trovi svolto nell'esercizio 11 della sezione 10: se il 40 per cento del tempo di un programma è attesa di memoria, raddoppiare il clock non raddoppia niente, e il tetto massimo si calcola in due righe.Dentro la CPU: unità di controllo, ALU, registri (e i nomi che cambiano fra i libri)
Prima di aprire la scatola, togliamo di mezzo la frase che fa più danni di tutte: «la CPU è il cervello del computer». È un'analogia, non una descrizione, e installa esattamente l'idea sbagliata — che lì dentro ci sia un posto dove stanno i programmi. Dentro una CPU la memoria si misura in centinaia di byte. Su un x86-64 i sedici registri general purpose da 64 bit fanno 16 × 8 = 128 byte in tutto: rispetto a un programma da 1 MB, cioè 1.000.000 di byte, sono 128 ÷ 1.000.000 = lo 0,0128 per cento. Il resto è altrove, e la CPU se lo va a prendere un pezzo alla volta.
Avvertenza sulle sigle, e serve subito. Da qui in avanti PC significa program counter, il registro che tiene l'indirizzo della prossima istruzione. La stessa sigla però è anche quella del personal computer, e in quel senso la ritroverai apposta più avanti: «entra nel tuo PC» nella sezione 7, «il primo IBM PC» nella sezione 8, due volte nell'errore 8 della sezione 11. Non è un capriccio di questa guida: è una collisione reale che trovi in tutti i libri, e l'unico rimedio è il contesto — dentro una traccia del ciclo macchina è sempre il contatore di programma, in una frase su un computer da tavolo non lo è mai. Quando in un compito scrivi PC, dichiara di quale dei due stai parlando.
I pezzi sono tre.1. L'unità di controllo, e il paletto che regge tutto
L'unità di controllo (CU, control unit) discende direttamente dalla CC del rapporto EDVAC. Il suo lavoro è decodificare l'istruzione e generare i segnali verso tutto il resto: verso l'ALU, verso i registri, verso la memoria.Su questo punto von Neumann pianta un paletto che è il nocciolo del programma memorizzato, e che i manuali quasi sempre saltano. Il § 2.3 distingue due cose: le istruzioni specifiche del problema, che vanno memorizzate come qualunque altro dato, e gli organi generali di controllo che le fanno eseguire, che sono circuiti fisici saldati una volta per tutte. Solo i secondi sono la CC.
Perché conta? Perché è la ragione per cui la stessa identica macchina fisica esegue oggi un videogioco e domani un foglio di calcolo, senza che tu cambi un filo. I fili sanno fare sempre le stesse dieci o cento cose; a cambiare è la sequenza di numeri che sta in memoria. Se questa distinzione non è chiara, tutto il resto della guida resta un elenco di sigle.
2. L'ALU, che non è una scatola nera
L'ALU (Arithmetic Logic Unit) discende dalla CA del rapporto. Von Neumann prevedeva le quattro operazioni +, −, × e ÷, e nel § 2.2 discuteva già se estenderla a radice quadrata, logaritmi e seno oppure restringerla togliendo la divisione.E qui la guida sull'algebra di Boole smette di essere teoria: l'ALU è fatta delle porte AND, OR e NOT di algebra di Boole e porte logiche, e il full adder costruito lì — somma con lo XOR, riporto con l'AND, otto in fila per sommare due byte — è letteralmente il circuito che eseguirà l'istruzione
ADD della prossima sezione. I flag Z (risultato zero) e C (riporto in uscita) non sono un argomento nuovo: sono le uscite di quel circuito, portate fuori e conservate in un registro. Nella sezione 6 li vedrai in due colonne della tabella di traccia.3. I registri, e cosa li distingue dalla memoria
I registri sono memorie interne alla CPU, le più veloci della macchina. Ma la differenza vera con la RAM non è la velocità: è che i registri non hanno un indirizzo. Alla cella 200 ci arrivi mettendo il numero 200 sul bus indirizzi; all'accumulatore ci arrivi perché la CU ha un filo che va lì. Si raggiungono per nome, non per numero. Chi in un compito scrive che i registri sono «memoria di primo livello indirizzabile» ha già perso mezzo punto.E un registro non contiene «un numero»: contiene una parola binaria di larghezza fissa. Il valore
0x10C8 che troverai fra poco è 0001 0000 1100 1000, e quei sedici bit si spezzano in 4 di codice operativo più 12 di indirizzo. È la lettura per gruppi di quattro bit della guida sui sistemi di numerazione: binario, decimale, esadecimale, ed è tutta la ragione per cui il contenuto dei registri si scrive in esadecimale e mai in decimale: in esadecimale i confini fra i campi si vedono a occhio, in decimale spariscono.La tabella dei nomi, perché i libri non vanno d'accordo
Questa è la tabella che serve davvero, e che quasi nessuna pagina italiana mette.| Funzione | Sigla principale | Altri nomi documentati | In italiano |
|---|---|---|---|
| Indirizzo della prossima istruzione | PC, program counter | IP instruction pointer (terminologia Intel), IAR instruction address register, instruction counter nella documentazione IBM del 1953 | contatore di programma, puntatore all'istruzione |
| Istruzione in corso | IR, instruction register | CIR current instruction register, standard nella didattica britannica | registro istruzione, registro istruzione corrente |
| Indirizzo della cella da leggere o scrivere | MAR, memory address register | — | registro indirizzi di memoria |
| Dato in transito da e verso la memoria | MDR, memory data register | MBR memory buffer register | registro dati di memoria, registro di transito |
| Operando e risultato dell'ALU | ACC, accumulator | A, AC | accumulatore |
Più due che compaiono in ogni CPU vera: il registro di stato o dei flag (status register, PSW, SR) e lo stack pointer (SP).
Le due avvertenze che valgono un voto
MDR e MBR sono la stessa cosa: due nomi per un registro solo, e se il tuo libro usa l'uno e il compagno di banco l'altro non state studiando due macchine diverse.MAR e MDR, invece, non sono affatto sinonimi fra loro — ed è l'errore che si vede più spesso nei compiti. Insieme formano l'interfaccia minima verso la memoria: l'uno dice dove, l'altro porta cosa. Sono anche larghi in modo diverso: il MAR è largo quanto il bus indirizzi, il MDR quanto la cella. Nella macchina della prossima sezione sono rispettivamente 12 e 16 bit, e già solo contando le linee si capisce chi è chi.
Ultima onestà, che nessuno dice. L'accumulatore singolo è un modello didattico, non una CPU vera. L'x86-64 ha 16 registri general purpose da 64 bit — la sigla che troverai nella sezione 7 è GPR, general purpose registers; l'8086 del 1978 ne aveva otto da 16 bit più i registri di segmento, l'instruction pointer e il registro dei flag; un microcontrollore AVR a 8 bit ne ha 32. Presentare l'accumulatore come il registro operativo di un processore moderno è falso. Presentarlo come il modello su cui si impara il ciclo macchina è corretto — ed è esattamente quello che facciamo adesso.
Il ciclo macchina passo per passo: la traccia di esecuzione, riga per riga
Questa è la sezione centrale della guida, ed è il pezzo che manca ovunque. Le altre pagine liquidano fetch, decode ed execute in due frasi a fase; nessuna segue un'istruzione vera con valori veri fino in fondo. Qui la seguiamo.
La notazione è
destinazione ← sorgente: la freccia va da dove il dato è a dove finisce. Nei blocchi incolonnati la scrivo <-, perché la freccia unicode manda in vacca l'allineamento.Le due convenzioni di questo modello, dichiarate prima di cominciare. Prima: ogni micro-operazione della tabella dura esattamente un ciclo di clock, riga di decodifica compresa. Non è una legge di natura, è la convenzione che rende i conti rifacibili — e senza dichiararla il calcolo dei cicli non sta in piedi. Seconda: contiamo il costo di un'istruzione in CPI, cicli per istruzione, che è il numero di righe di tabella che quell'istruzione occupa. La formula completa in cui il CPI entra la trovi nella sezione 9.
Le tre fasi, in ordine
FETCH (prelievo), quattro micro-operazioni.1)
MAR ← PC — il PC contiene l'indirizzo della prossima istruzione, e viene copiato nel MAR. Il PC non si svuota: copiare non è spostare.2)
MDR ← Memoria[MAR] — la memoria risponde, e la parola torna nel MDR viaggiando sul bus dati.3)
PC ← PC + 1 — tieni d'occhio questo passo, ci torniamo fra tre righe.4)
IR ← MDR — l'istruzione passa nel registro istruzione, dove codice operativo e operando possono finalmente essere separati.E qui la nota che molti libri numerano come se fosse un passo a sé, sbagliando i conti di tutto il capitolo: contemporaneamente al passo 2 l'indirizzo esce sul bus indirizzi e la CU alza il segnale READ sul bus di controllo. Non è un ciclo in più: è ciò che rende possibile il passo
MDR ← Memoria[MAR]. Se lo conti come quinto passo, l'istruzione ti costa 9 cicli invece di 8, il programma 27 invece di 24, e tutti i tempi finali saltano.DECODE (decodifica), una micro-operazione. La CU legge l'IR e separa il codice operativo dal campo indirizzo. Poi manda i segnali: all'ALU, se c'è da calcolare; di nuovo alla memoria, se c'è da prelevare un operando.
EXECUTE (esecuzione), i cinque casi di questa macchina. Prima di scrivere questa parte, una nota di notazione, perché il simbolo è nuovo:
IR[11..0] significa i dodici bit di destra dell'IR, numerati da 11 (il più a sinistra dei dodici) fino a 0 (l'ultimo a destra). Sono il campo indirizzo, e l'opcode resta fuori.•
LOAD indirizzo → MAR ← IR[11..0], poi MDR ← Memoria[MAR], poi ACC ← MDR. Tre cicli. Aggiorna il flag Z.•
ADD indirizzo → MAR ← IR[11..0], poi MDR ← Memoria[MAR], poi ACC ← ACC + MDR. Tre cicli, due accessi alla memoria per una sola istruzione. Aggiorna Z e C.•
STORE indirizzo → MAR ← IR[11..0], poi MDR ← ACC, poi Memoria[MAR] ← MDR con il segnale WRITE. Tre cicli. Non tocca i flag.•
JMP indirizzo → PC ← IR[11..0], e basta. Un ciclo, nessun accesso alla memoria, nessun flag toccato.•
JZ indirizzo (salto condizionato) → se Z = 1 allora PC ← IR[11..0]; se Z = 0 non si scrive niente e il PC resta quello già incrementato nel fetch. Un ciclo in entrambi i casi.Il passo 3 decide se hai capito il ciclo macchina o no
Il PC si incrementa durante il fetch, prima dell'esecuzione, e non alla fine del ciclo.Non è un dettaglio di ordine: serve esattamente perché un salto, in fase di esecuzione, possa sovrascrivere il valore appena incrementato. Se il PC venisse incrementato dopo l'esecuzione, ogni
JMP scriverebbe la destinazione nel PC e un istante dopo l'incremento la distruggerebbe: i salti non funzionerebbero, e con loro non funzionerebbero i cicli, le condizioni, le chiamate a funzione. Cioè: niente.Se di questa pagina ti porti via una riga sola, portati via questa. E più avanti la vedrai succedere davvero, al passo 36 della traccia.
La macchina su cui tracciamo
Parole da 16 bit, bus indirizzi a 12 bit, 4.096 celle da 16 bit ciascuna. Formato dell'istruzione: 4 bit di codice operativo più 12 di indirizzo. codice nome che cosa fa cicli
------ ----- -------------------------------------- -----
0001 LOAD ACC <- M[indirizzo] 8
0010 ADD ACC <- ACC + M[indirizzo] 8
0011 STORE M[indirizzo] <- ACC 8
0100 JMP PC <- indirizzo 6
0101 JZ se Z=1 PC <- indirizzo, altrimenti nulla 6
flag: Z = 1 quando il valore appena scritto nell'ACC e' 0x0000
C = riporto in uscita dell'ultima ADD
LOAD e ADD aggiornano Z; solo ADD aggiorna C;
STORE, JMP e JZ non toccano nessuno dei due.
All'accensione ACC = 0x0000, quindi Z = 1 e C = 0.
Stato iniziale: PC = 0x010, ACC = 0x0000, Z = 1, C = 0, M[0x010] = 0x10C8, M[0x0C8] = 0x0025.Prima di tracciare si decodifica a mano. Sempre.
0x10C8 in binario: 0001 0000 1100 1000
^^^^ ^^^^^^^^^^^^^^
opcode indirizzo
opcode 0001 = 1 -> LOAD
indirizzo 0000 1100 1000 = 0x0C8 = 200
Istruzione: LOAD 200 -> ACC <- contenuto della cella 200
La traccia di una sola istruzione
Ogni riga mostra lo stato dopo il passo. I trattini indicano contenuto non significativo.Passo Micro-operazione PC IR MAR MDR ACC Z C ----- -------------------------------- ----- ------ ----- ------ ------ - - 0 (stato iniziale) 0x010 ---- ---- ---- 0x0000 1 0 1 MAR <- PC 0x010 ---- 0x010 ---- 0x0000 1 0 2 MDR <- M[MAR] 0x010 ---- 0x010 0x10C8 0x0000 1 0 3 PC <- PC + 1 0x011 ---- 0x010 0x10C8 0x0000 1 0 4 IR <- MDR 0x011 0x10C8 0x010 0x10C8 0x0000 1 0 5 decodifica opcode 0001 = LOAD 0x011 0x10C8 0x010 0x10C8 0x0000 1 0 6 MAR <- IR[11..0] 0x011 0x10C8 0x0C8 0x10C8 0x0000 1 0 7 MDR <- M[MAR] 0x011 0x10C8 0x0C8 0x0025 0x0000 1 0 8 ACC <- MDR 0x011 0x10C8 0x0C8 0x0025 0x0025 0 0Fetch ai passi 1-4, decode al 5, execute ai 6-8. Alla fine
ACC = 0x0025, cioè 37 in decimale; PC = 0x011, cioè punta già all'istruzione successiva; IR = 0x10C8, cioè conserva l'istruzione in corso. E guarda la colonna Z: era 1 perché l'accumulatore era vuoto, al passo 8 diventa 0 perché adesso dentro c'è 37. Costo: 8 cicli, quindi CPI = 8 per questa istruzione.Due errori da evitare qui. Al passo 6 non si scrive
MAR ← IR: nel MAR vanno solo i 12 bit di indirizzo, l'opcode resta all'unità di controllo. E il MAR è largo 12 bit, quindi i 16 bit dell'IR non ci starebbero nemmeno fisicamente.Il programma di tre istruzioni
Stessa macchina. In memoria:Indirizzo Contenuto Significato Codifica --------- --------- ----------------------- ---------------------- 0x010 0x10C8 LOAD 200 opcode 0001, ind. 0x0C8 0x011 0x20C9 ADD 201 opcode 0010, ind. 0x0C9 0x012 0x30CA STORE 202 opcode 0011, ind. 0x0CA 0x0C8 0x0025 dato: 37 0x0C9 0x000A dato: 10 0x0CA 0x0000 spazio per il risultato
Passo Micro-operazione PC IR MAR MDR ACC Z C
----- -------------------------------- ----- ------ ----- ------ ------ - -
0 (stato iniziale) 0x010 ---- ---- ---- 0x0000 1 0
--- ISTRUZIONE 1: LOAD 200 ---
1 MAR <- PC 0x010 ---- 0x010 ---- 0x0000 1 0
2 MDR <- M[MAR] 0x010 ---- 0x010 0x10C8 0x0000 1 0
3 PC <- PC + 1 0x011 ---- 0x010 0x10C8 0x0000 1 0
4 IR <- MDR 0x011 0x10C8 0x010 0x10C8 0x0000 1 0
5 decodifica 0001 = LOAD 0x011 0x10C8 0x010 0x10C8 0x0000 1 0
6 MAR <- IR[11..0] 0x011 0x10C8 0x0C8 0x10C8 0x0000 1 0
7 MDR <- M[MAR] 0x011 0x10C8 0x0C8 0x0025 0x0000 1 0
8 ACC <- MDR 0x011 0x10C8 0x0C8 0x0025 0x0025 0 0
--- ISTRUZIONE 2: ADD 201 ---
9 MAR <- PC 0x011 0x10C8 0x011 0x0025 0x0025 0 0
10 MDR <- M[MAR] 0x011 0x10C8 0x011 0x20C9 0x0025 0 0
11 PC <- PC + 1 0x012 0x10C8 0x011 0x20C9 0x0025 0 0
12 IR <- MDR 0x012 0x20C9 0x011 0x20C9 0x0025 0 0
13 decodifica 0010 = ADD 0x012 0x20C9 0x011 0x20C9 0x0025 0 0
14 MAR <- IR[11..0] 0x012 0x20C9 0x0C9 0x20C9 0x0025 0 0
15 MDR <- M[MAR] 0x012 0x20C9 0x0C9 0x000A 0x0025 0 0
16 ACC <- ACC + MDR 0x012 0x20C9 0x0C9 0x000A 0x002F 0 0
--- ISTRUZIONE 3: STORE 202 ---
17 MAR <- PC 0x012 0x20C9 0x012 0x000A 0x002F 0 0
18 MDR <- M[MAR] 0x012 0x20C9 0x012 0x30CA 0x002F 0 0
19 PC <- PC + 1 0x013 0x20C9 0x012 0x30CA 0x002F 0 0
20 IR <- MDR 0x013 0x30CA 0x012 0x30CA 0x002F 0 0
21 decodifica 0011 = STORE 0x013 0x30CA 0x012 0x30CA 0x002F 0 0
22 MAR <- IR[11..0] 0x013 0x30CA 0x0CA 0x30CA 0x002F 0 0
23 MDR <- ACC 0x013 0x30CA 0x0CA 0x002F 0x002F 0 0
24 M[MAR] <- MDR 0x013 0x30CA 0x0CA 0x002F 0x002F 0 0
Verifica dell'aritmetica al passo 16: 0x0025 + 0x000A = 37 + 10 = 47 = 0x002F. Corretto, e siccome 47 non è zero e non c'è riporto oltre il sedicesimo bit, Z e C restano 0. E la memoria alla fine: M[0x0CA] = 0x002F, dove prima c'era 0x0000.Tre cose da guardare, e sono il motivo per cui la tabella vale più della spiegazione.
Primo: il fetch è identico tutte e tre le volte, passi 1-4, 9-12, 17-20. Cambia solo l'execute. Il ciclo macchina non è una procedura diversa per ogni istruzione: è sempre la stessa testa con code diverse.
Secondo: al passo 9 il MDR contiene ancora
0x0025, lasciato lì dalla LOAD. I registri non si azzerano fra un'istruzione e l'altra, e chi nella traccia scrive dei trattini a ogni cambio di istruzione sta descrivendo una macchina che non esiste.Terzo: nella STORE il MDR gira al contrario. Nella LOAD e nella ADD si riempie dalla memoria; qui si riempie dalla CPU (passo 23) e si svuota verso la memoria (passo 24). Chi scrive
MDR ← M[MAR] anche nella STORE cancella il risultato appena calcolato. E chi salta il passo 23 scrivendo direttamente Memoria[MAR] ← ACC sta collegando l'accumulatore al bus dati, cosa che nel disegno non c'è.Costo di queste tre istruzioni: 24 cicli, quindi CPI medio 24 ÷ 3 = 8. A 100 MHz il periodo di clock è T = 1 diviso 100 × 10⁶ Hz = 10 ns, quindi questa parte dura 24 × 10 ns = 240 ns.
E adesso i salti, che sono il pezzo che nessuno traccia
Il programma non è finito. Nelle due celle successive c'è questo:Indirizzo Contenuto Significato Codifica --------- --------- ----------------------- ---------------------- 0x013 0x5016 JZ 0x016 opcode 0101, ind. 0x016 0x014 0x4010 JMP 0x010 opcode 0100, ind. 0x010Si riparte dallo stato lasciato dal passo 24, senza azzerare niente.
Passo Micro-operazione PC IR MAR MDR ACC Z C
----- -------------------------------- ----- ------ ----- ------ ------ - -
24 (stato lasciato dalla STORE) 0x013 0x30CA 0x0CA 0x002F 0x002F 0 0
--- ISTRUZIONE 4: JZ 0x016 ---
25 MAR <- PC 0x013 0x30CA 0x013 0x002F 0x002F 0 0
26 MDR <- M[MAR] 0x013 0x30CA 0x013 0x5016 0x002F 0 0
27 PC <- PC + 1 0x014 0x30CA 0x013 0x5016 0x002F 0 0
28 IR <- MDR 0x014 0x5016 0x013 0x5016 0x002F 0 0
29 decodifica 0101 = JZ 0x014 0x5016 0x013 0x5016 0x002F 0 0
30 Z = 0 -> nessuna scrittura 0x014 0x5016 0x013 0x5016 0x002F 0 0
--- ISTRUZIONE 5: JMP 0x010 ---
31 MAR <- PC 0x014 0x5016 0x014 0x5016 0x002F 0 0
32 MDR <- M[MAR] 0x014 0x5016 0x014 0x4010 0x002F 0 0
33 PC <- PC + 1 0x015 0x5016 0x014 0x4010 0x002F 0 0
34 IR <- MDR 0x015 0x4010 0x014 0x4010 0x002F 0 0
35 decodifica 0100 = JMP 0x015 0x4010 0x014 0x4010 0x002F 0 0
36 PC <- IR[11..0] 0x010 0x4010 0x014 0x4010 0x002F 0 0
Guarda il PC ai passi 33 e 36. Al passo 33 il fetch lo ha portato a 0x015, che è la cella dopo la JMP. Al passo 36 l'esecuzione ci scrive sopra 0x010, e il valore incrementato sparisce senza aver mai servito a niente. È il salto che sovrascrive il PC, esattamente il meccanismo di cui parlavamo prima: se l'incremento arrivasse dopo, al passo 37 il PC tornerebbe a 0x011 e il salto sarebbe cancellato. Con questa istruzione il programma ricomincia da 0x010, e hai un ciclo infinito. Non è però il più corto scrivibile: con questo stesso set il più corto è una sola JMP che punta al proprio indirizzo, una istruzione e 6 cicli. Questo qui ne gira cinque, e costa 36 cicli a ogni giro.E la JZ del passo 30 non ha saltato perché Z valeva 0. Ecco il confronto, sullo stesso passo 30, con il solo Z cambiato:
caso reale caso alternativo
come ci si arriva ACC = 0x002F ACC = 0x0000
(37 + 10 = 47) (se in 0x0C8 e in
0x0C9 ci fosse 0x0000)
flag Z prima del passo 30 0 1
passo 30 nessuna PC <- IR[11..0]
scrittura
PC dopo il passo 30 0x014 0x016
prossima istruzione prelevata quella in 0x014 quella in 0x016
Costo dei salti: 6 cicli ciascuno, quattro di fetch, uno di decodifica, uno di esecuzione. Nessun accesso alla memoria in fase di esecuzione, ed è per questo che costano meno di LOAD, ADD e STORE.Il conto totale del programma completo, e questo è il numero da portare a casa:
3 istruzioni da 8 cicli = 24 2 istruzioni da 6 cicli = 12 totale = 36 cicli per 5 istruzioni CPI medio = 36 : 5 = 7,2 a 100 MHz (T = 10 ns) = 36 x 10 ns = 360 nsNota che il CPI medio non è una proprietà del processore: è il risultato del miscuglio di istruzioni che il programma esegue. Tre LOAD-ADD-STORE e due salti danno 7,2; un programma fatto di soli salti darebbe 6. È la ragione per cui nella sezione 9 il CPI compare come fattore a sé, accanto al numero di istruzioni.
Qui si agganciano gli algoritmi
Questa tabella è la tabella di traccia della guida su algoritmi e diagrammi di flusso, applicata ai registri della macchina invece che alle variabili del tuo pseudocodice. Stesso strumento, un livello più in basso: una colonna per ogni cosa che può cambiare, una riga per ogni passo, e lo stato scritto dopo.E il rombo del diagramma di flusso, il blocco di decisione con le sue due uscite V e F, qui smette di essere un simbolo e diventa una cosa fisica: è la JZ del passo 30, cioè un valore scritto nel PC invece che nel PC incrementato, e la condizione è un bit di flag. La freccia all'indietro del ciclo è la JMP del passo 36. Il diagramma non descrive la macchina, descrive quello che la macchina esegue. E il motivo per cui può eseguirlo è il passo 3.
Avvertenza, e va detta prima che qualcuno ti corregga all'orale. Questo è il modello sequenziale. I processori reali usano pipeline, esecuzione superscalare, fuori ordine e speculativa: perfino un microcontrollore AVR o un Cortex-M preleva già l'istruzione successiva mentre esegue la corrente. Il modello a passi resta lo strumento didattico giusto — è il solo con cui puoi scrivere una traccia — ma va dichiarato come modello, non spacciato per fotografia.
Pubblicità
La gerarchia delle memorie: i numeri veri, misurati su processori con un nome
Qui non ci sono stime né ordini di grandezza vaghi. Ci sono misure su processori identificati, e se un numero non ha un processore accanto non serve a niente.
Intel Core i7-1065G7 (Ice Lake, 10 nm, fino a 3,9 GHz)
| Livello | Capacità | Latenza misurata |
|---|---|---|
| L1d (dati) | 48 KB | 5 cicli |
| L2 | 512 KB | 13 cicli |
| L3 | 8 MB | 42 cicli |
| RAM LPDDR4-3733 | — | 42 cicli più 87 ns |
Quell'ultima riga si legge così, ed è istruttiva: un accesso alla RAM costa prima i 42 cicli spesi a cercare invano nella L3, e poi altri 87 ns. A 3,9 GHz un ciclo dura 1 diviso 3,9 × 10⁹ Hz = 0,256 ns, quindi 42 cicli sono 10,8 ns e il totale è circa 98 ns. Un miss non è gratis: paghi anche la ricerca fallita.
Nota sull'unità, perché in questa guida distinguiamo: i costruttori scrivono KB e MB, ma per le cache l'unità è sempre binaria. I 48 KB di L1d sono 48 KiB, cioè 48 × 1.024 = 49.152 byte.
AMD Ryzen 9 7950X (Zen 4, boost 5,7 GHz)
| Livello | Capacità | Latenza misurata |
|---|---|---|
| L1i (istruzioni) e L1d (dati) | 32 KB ciascuna, per core | 4 cicli, circa 0,7 ns |
| L2 | 1 MB per core, il doppio dei 512 KB di Zen 3 | 14 cicli, circa 2,5 ns |
| L3 | 32 MB per CCD (core complex die, il gruppo di core inciso su un unico chiplet), e il 7950X ne ha due: quindi 64 MB | circa 8-9 ns |
| RAM DDR5-6000 | — | 73,35 ns |
Quella prima riga è anche la risposta al rimando della sezione 3: L1i è la cache istruzioni, L1d la cache dati, e il fatto che siano due oggetti distinti sullo stesso livello è il punto in cui l'architettura Harvard entra nel tuo PC.
Controlla tu il primo numero, è la verifica che vale più di tutte: a 5,7 GHz il periodo è 1 diviso 5,7 × 10⁹ = 0,175 ns, e 4 × 0,175 = 0,70 ns. Torna. Fai lo stesso con la L3: 8 ns diviso 0,175 ns dà circa 46 cicli, non 9. Se trovi in giro «L3 di Zen 4: 9 cicli», qualcuno ha scambiato i nanosecondi per cicli.
Agli estremi della scala: i registri costano circa 1 ciclo e sull'x86-64 i GPR (general purpose registers, i registri di uso generale) sono in tutto 128 byte; un SSD NVMe sta a 20-70 µs in lettura casuale; un disco meccanico a 5-10 ms.
Il numero dell'hard disk si rifà in trenta secondi
Questo conto vale la pena farlo in classe, perché mostra da dove esce il numero invece di farlo imparare a memoria — e mostra anche quale metà del numero si calcola e quale no.Un disco a 7.200 giri al minuto compie 7.200 ÷ 60 = 120 giri al secondo, quindi un giro completo dura 1 ÷ 120 = 8,33 ms. Attenzione: quegli 8,33 ms sono la durata del giro, non il tempo di accesso, e confonderli con gli «8 ms» della tabella della sezione 1 è un classico. Il tempo di accesso si compone di due pezzi:
latenza rotazionale media mezzo giro = 8,33 : 2 = 4,17 ms <- aritmetica tempo di ricerca (seek) spostamento della testina = 4-8 ms <- dato meccanico --------------------------------------------------------------- tempo di accesso somma dei due = 5-10 msLa prima riga si calcola dai giri al minuto: in media, quando la testina è già sulla traccia giusta, il settore che cerchi è a mezzo giro di distanza. La seconda non si calcola dagli RPM: è il tempo che il braccio impiega a spostarsi fra le tracce, sta sui 4-8 ms per i dischi da 3,5 pollici, e lo leggi sulla scheda tecnica. Il totale è 5-10 ms, ed è tutto meccanica, non elettronica.
La scala che rende l'idea
I nanosecondi non dicono niente a nessuno. Trasformiamoli — ma dichiarando il clock di riferimento, altrimenti la scala non è verificabile. Prendiamo un processore a 3 GHz: un ciclo dura un terzo di nanosecondo, che si scrive 0,33 ns, e diciamo che quel ciclo duri un secondo. Tieni a mente la forma esatta, perché i cicli si contano moltiplicando i nanosecondi per 3: se dividi per lo 0,33 arrotondato ti escono 303 cicli invece di 300, e ti sembra di aver sbagliato tu.livello tempo reale cicli (ns x 3) scala "1 ciclo = 1 s" -------- ------------ ---------------- --------------------- registro ~ 0,33 ns 1 1 secondo cache L1 ~ 1,3 ns 4 4 secondi cache L2 ~ 4,7 ns 14 14 secondi cache L3 ~ 15 ns 45 45 secondi RAM ~ 100 ns 300 5 minuti SSD NVMe ~ 50 us 1,5 x 10^5 1,7 giorni HDD ~ 8 ms 2,4 x 10^7 278 giorniI due conti in fondo, che sono quelli che quasi tutte le versioni in giro sbagliano: 50 µs sono 50.000 ns, e × 3 = 1,5 × 10⁵ cicli; poi 1,5 × 10⁵ secondi ÷ 86.400 = 1,7 giorni. Allo stesso modo 8 ms sono 8.000.000 ns, e × 3 = 2,4 × 10⁷ cicli, e 2,4 × 10⁷ secondi ÷ 86.400 = 278 giorni, cioè poco più di nove mesi. Fra prendere un dato da un registro e prenderlo da un disco meccanico c'è lo stesso rapporto che c'è fra un secondo e un anno scolastico intero, ricreazioni comprese.
Ed è questa la ragione per cui esiste la cache. Non è un accessorio: è l'unico modo di non pagare i 5 minuti tutte le volte. Ed è anche il motivo per cui una percentuale di miss apparentemente ridicola pesa moltissimo — un hit rate del 95 per cento, che sembra ottimo, può più che raddoppiare il tempo medio di accesso. Il conto lo fai per esteso nell'esercizio 8.
Due avvertenze di onestà
La tabella di Jeff Dean è datata sulla parte storage. La celeberrima Latency Numbers Every Programmer Should Know (L1 = 0,5 ns, L2 = 7 ns, RAM = 100 ns, seek del disco = 10 ms) circola ovunque, e per cache e RAM regge ancora benissimo. Ma i suoi valori per la memoria di massa risalgono a circa il 2012: la riga «lettura casuale di 4 KB da SSD = 150 µs» è vecchia di un ordine di grandezza, visto che gli NVMe attuali stanno a 20-70 µs. Se la citi, dillo. Citare un numero senza la sua data è il modo più elegante di sbagliare.«L1, L2, L3» è già una semplificazione in movimento. Nei P-core Lion Cove degli Intel Core Ultra 200S (Arrow Lake) c'è un livello in più: L0 dati da 48 KB, poi L1 dati da 192 KB, L1 istruzioni da 64 KB, L2 da 3 MB per P-core (4 MB condivisi per ogni modulo di quattro E-core) e L3 fino a 36 MB. La gerarchia si allunga; la logica no. Il principio resta quello del conto qui sopra: più è veloce, meno ce n'è, e più vicino sta.
I bus e il conto 2ⁿ: quanta memoria posso indirizzare
Tre linee, tre mestieri diversi. Confonderli è la premessa di metà degli errori negli esercizi.
| Bus | Cosa trasporta | Verso | Che cosa decide |
|---|---|---|---|
| Bus dati | il contenuto delle celle | bidirezionale, si legge e si scrive | quanti bit si trasferiscono per ogni accesso |
| Bus indirizzi | l'indirizzo della cella | unidirezionale, dalla CPU alla memoria | quanta memoria è indirizzabile |
| Bus di controllo | READ, WRITE, clock, interrupt, ready | misto | se si legge o si scrive, e quando |
Il bus di controllo sembra il meno importante e non lo è. Torna alla traccia della sezione 6: il passo 7 e il passo 24 mettono sul bus indirizzi lo stesso tipo di numero e sul bus dati lo stesso tipo di parola. A distinguere una lettura da una scrittura è soltanto la linea di controllo. Senza di lei la memoria riceve un indirizzo e non sa che farsene.
La regola, con la parola giusta
Ogni linea del bus indirizzi porta un bit, e ogni bit raddoppia le combinazioni. Con n linee le combinazioni distinte sono 2ⁿ, numerate da 0 a 2ⁿ − 1, e ciascuna individua una cella.Celle. Non byte. La dimensione totale è 2ⁿ × ampiezza della cella, e fa 2ⁿ byte solo quando la cella è di un byte. È l'errore singolo più frequente di tutto il capitolo, e nasce dall'aver memorizzato la formula sbagliata.
È la stessa potenza di due della guida sui sistemi di numerazione: binario, decimale, esadecimale: ogni linea in più raddoppia gli indirizzi possibili esattamente come ogni cifra binaria in più raddoppia i numeri rappresentabili. Non è un'analogia, è lo stesso conto applicato al rame.
n celle indirizzabili = 2^n con celle da 1 byte macchina reale -- ------------------------- ------------------- ------------------------------- 10 1.024 1 KiB 16 65.536 64 KiB 8080, Z80, 6502 20 1.048.576 1 MiB Intel 8086 e 8088 (1978) 24 16.777.216 16 MiB Intel 80286 32 4.294.967.296 4 GiB limite dei sistemi a 32 bit 48 281.474.976.710.656 256 TiB x86-64, forma canonica 57 144.115.188.075.855.872 128 PiB x86-64, paginazione a 5 livelli
L'esempio che va fatto per intero
Un esercizio da verifica suona così: bus indirizzi a 24 bit, celle da 16 bit, quanta memoria? celle = 2^24 = 16.777.216 celle
ampiezza = 16 bit = 16 / 8 = 2 byte per cella
totale = 16.777.216 x 2 byte = 33.554.432 byte
= 33.554.432 / 1.024 = 32.768 KiB
= 32.768 / 1.024 = 32 MiB <-- non 16 MiB
Chi risponde 16 MiB ha letto 2²⁴ e si è fermato lì. La stessa trappola, girata al contrario, sta nella macchina della sezione 6: 4.096 celle da 16 bit fanno 4.096 × 2 = 8.192 byte = 8 KiB, non 4 KiB.La riga dei 20 bit merita il suo paragrafo
L'Intel 8086, lanciato l'8 giugno 1978 a 5 MHz, aveva bus dati a 16 bit e bus indirizzi a 20 bit. Venti linee, dunque 2²⁰ = 1.048.576 byte = 1 MiB di spazio fisico indirizzabile. E qui viene il punto: il famigerato tetto di 1 MB del DOS non è una scelta di software, non è una svista dei programmatori dell'epoca e non è pigrizia di Microsoft. È una conseguenza aritmetica diretta della larghezza di un fascio di fili. Sopra quel numero non c'era niente da programmare, perché non c'era nessun indirizzo da scrivere.E la controprova sta nel modello accanto. L'8088 — quello del primo IBM PC — ha gli stessi 20 bit di indirizzo e solo 8 bit di dato esterno. Indirizza esattamente la stessa memoria, 1 MiB, e la trasferisce alla metà della velocità: le istruzioni x86 lunghe più di un byte gli costano più accessi, il che è precisamente l'argomento del costo che hai visto nella sezione 3. Il bus dati cambia la banda, non lo spazio. Se in un esercizio ti danno tutti e due i numeri e tu usi quello del bus dati per calcolare la capacità, hai risposto a una domanda che nessuno ti aveva fatto.
Il chiarimento che quasi tutti sbagliano
Un processore «a 64 bit» non ha 64 linee di indirizzo, e nessun processore esistente indirizza 2⁶⁴ byte.L'architettura x86-64 impone la forma canonica: gli indirizzi virtuali validi vanno da 0 fino a
00007FFF FFFFFFFF, e poi riprendono da FFFF8000 00000000 in su. Cioè 48 bit realmente implementati, per 256 TiB di spazio virtuale utilizzabile. Con la paginazione a cinque livelli introdotta da Intel si sale a 57 bit, cioè 128 PiB. Sul lato fisico AMD64 arriva a 48 bit, con l'architettura predisposta per 52 bit (4 PiB); le prime implementazioni si fermavano a 40 bit, cioè 1 TiB.Perché non cablarle tutte e 64? Perché ogni linea di indirizzo costa piedini, piste, consumo e transistor nelle tabelle delle pagine, e 256 TiB sono già più memoria di quanta ne esista in un data center. Si implementa quello che serve.
La lezione da portarsi via è più larga del numero: «a 64 bit» è una dichiarazione architetturale, non una misura di quello che il chip ha davvero dentro. Separare il modello dall'implementazione è, con l'incremento del PC durante il fetch, la seconda cosa che distingue chi ha capito questa materia da chi l'ha imparata a memoria.
Il clock: perché i gigahertz non misurano la velocità
Se c'è un numero che tutti sanno recitare di un processore, è quello: 3,5 GHz. Ed è il numero da cui parte l'unica frase che ti fa perdere punti in ogni verifica su questo argomento: «il mio è da 3,5 GHz, quindi è più veloce del tuo da 2,8». La frase è sbagliata, ma non è stupida: è vera dentro una famiglia di processori, e chi la dice sta generalizzando un confronto legittimo a un caso in cui non vale più. Smontiamola partendo da che cosa sia fisicamente il clock.
Un metronomo, non un motore
Il segnale nasce da un oscillatore al quarzo, che produce un'onda a frequenza fissa; un circuito elettronico la trasforma in onda quadra, cioè in una successione netta di 0 e 1; un moltiplicatore ne genera un multiplo fisso; e la rete di distribuzione del clock la porta a tutti i componenti che devono restare sincronizzati fra loro.Quello che il clock non fa è far lavorare la CPU. Non spinge niente: scandisce l'istante in cui i risultati sono considerati stabili. Fra un fronte e il successivo i segnali si assestano nei circuiti, e al fronte dopo vengono letti. È un metronomo, non un motore — e i musicisti non suonano più forte perché il metronomo va più veloce, suonano più in fretta finché ci riescono.
Frequenza e periodo: uno l'inverso dell'altro
La relazione è T = 1/f, e va saputa nei due versi.| Frequenza | Periodo T = 1/f |
|---|---|
| 5 MHz (Intel 8086, 1978) | 200 ns |
| 100 MHz (la macchina della sezione 6) | 10 ns |
| 1 GHz | 1 ns |
| 3 GHz | 0,33 ns |
| 5,7 GHz | 0,175 ns |
E adesso il confronto che rende quei numeri qualcosa di reale. In 0,33 ns la luce nel vuoto percorre circa 10 cm (3 × 10⁸ m/s × 3,33 × 10⁻¹⁰ s ≈ 0,1 m). Un segnale in una pista di rame viaggia a circa metà o due terzi di quella velocità, quindi ne fa 5-7 cm.
Rileggi la riga: a 3 GHz, in un solo ciclo di clock, un segnale non attraversa nemmeno tutta la scheda madre. La dimensione fisica del chip non è più un dettaglio meccanico, è diventata un vincolo elettrico. Ed è la prima ragione per cui la frequenza non può salire all'infinito.
L'equazione che sostituisce il confronto fra gigahertz
Il tempo di esecuzione di un programma non dipende da un fattore, ma da tre:Tempo CPU = numero di istruzioni × CPI × durata del ciclo di clock
• il numero di istruzioni dipende dal programma, dal compilatore e dal set di istruzioni — cioè, a monte, dall'algoritmo che hai scelto, quello della guida su algoritmi e diagrammi di flusso;• il CPI (cicli per istruzione, la sigla che hai già usato nella sezione 6) dipende dalla microarchitettura — pipeline, unità di esecuzione, cache, predizione dei salti — e anche dal miscuglio di istruzioni del programma, come hai visto quando i due salti hanno portato il CPI medio da 8 a 7,2;
• solo la durata del ciclo è l'inverso della frequenza.
Il clock è uno dei tre fattori, e non è detto che sia il dominante. Chi confronta due processori guardando i gigahertz sta confrontando un terzo dell'equazione e assumendo che gli altri due siano uguali.
Da qui il corollario che va detto per esteso, perché quasi nessuno lo dice: una CPU a 3 GHz non esegue tre miliardi di istruzioni al secondo. Con CPI 1,5 ne esegue 3 × 10⁹ ÷ 1,5 = due miliardi; una CPU superscalare, che ritira più di un'istruzione per ciclo, può superarne tre. Il clock conta i cicli, non le istruzioni.
Il mito dei megahertz è un fatto datato, non un'opinione
Non è una tesi da manuale: è un episodio con una data e un palco. Keynote di Steve Jobs al Macworld Expo di New York, 18 luglio 2001. Un PowerPC G4 a 867 MHz completa un compito in 45 secondi; un Pentium 4 a 1,7 GHz impiega 82 secondi. Clock 1,96 volte più alto (1700 ÷ 867), tempo 1,82 volte maggiore (82 ÷ 45). Da lì in avanti il fenomeno ha un nome, megahertz myth, e fu Apple stessa a battezzarlo dal palco.La regola operativa che ne segue: il confronto per frequenza è valido solo fra processori della stessa famiglia e dello stesso progetto. Un 80486 a 50 MHz è davvero circa il doppio di un 80486 a 25 MHz. Un ARM e un x86 alla stessa frequenza non si possono confrontare affatto.
E perché i gigahertz si sono fermati: è fisica
La soglia dei 3 GHz viene raggiunta nel 2002. Poi la corsa si ferma, e non per scelta commerciale.Nel maggio 2004 Intel cancella Tejas e Jayhawk, i successori del Pentium 4. Il motivo è documentato: un campione Tejas a 90 nm dissipava 150 W a soli 2,8 GHz, contro gli ~84 W di un Prescott alla stessa frequenza. L'obiettivo dichiarato per Tejas nel 2003 era 7 GHz o più: non fu mai raggiunto, e il progetto morì. Dietro c'è la fine dello scaling di Dennard, intorno al 2005: rimpicciolire i transistor smette di ridurre proporzionalmente il consumo. È il power wall, il muro della potenza. La risposta dell'industria fu cambiare strada: microarchitetture più efficienti e, soprattutto, più core.
Ecco la frase da portarti in verifica, ed è tutta aritmetica:
Dal 1978 al 2002 la frequenza dei processori è cresciuta circa 600 volte (da 5 MHz a 3 GHz: 3000 ÷ 5 = 600). Dal 2002 a oggi, sì e no 2 volte: si sta nella fascia 4-6 GHz, e l'estremo alto diviso il punto di partenza, 6 ÷ 3, fa esattamente 2. Eppure i calcolatori sono enormemente più veloci. Tutto il guadagno degli ultimi vent'anni viene da CPI, cache, parallelismo e numero di core: cioè esattamente dai fattori che i gigahertz non misurano.
Dodici esercizi svolti passo passo
Le convenzioni si dichiarano una volta sola, in testa, e valgono per tutti e dodici. Metà degli «errori dello studente» su questo argomento sono in realtà esercizi in cui la convenzione non era scritta da nessuna parte. Qui i prefissi si applicano soltanto: la loro costruzione sta nella guida sui sistemi di numerazione: binario, decimale, esadecimale.
1 KB = 10^3 B = 1.000 B 1 KiB = 2^10 B = 1.024 B 1 MB = 10^6 B = 1.000.000 B 1 MiB = 2^20 B = 1.048.576 B 1 GB = 10^9 B 1 GiB = 2^30 B = 1.073.741.824 B b = bit (minuscolo) B = byte (maiuscolo) 1 B = 8 b 2^1 = 2 2^8 = 256 2^15 = 32.768 2^20 = 1.048.576 2^2 = 4 2^9 = 512 2^16 = 65.536 2^24 = 16.777.216 2^3 = 8 2^10 = 1.024 2^17 = 131.072 2^30 = 1.073.741.824 2^4 = 16 2^11 = 2.048 2^18 = 262.144 2^32 = 4.294.967.296 2^5 = 32 2^12 = 4.096 2^19 = 524.288 2^6 = 64 2^13 = 8.192 2^7 = 128 2^14 = 16.384
Esercizi 1 e 2 — Dal bus indirizzi alla memoria (e ritorno)
Testo 1. Bus indirizzi a 16 linee: quante celle? Se ogni cella è 1 byte, quanti KiB? E quante linee per indirizzare 1.048.576 celle? E per 1.000.000?La mossa che sblocca. Ogni linea porta un bit e ogni bit raddoppia le combinazioni: con n linee gli indirizzi distinti sono 2ⁿ, numerati da 0 a 2ⁿ − 1.
• 2¹⁶ = 65.536 celle; 65.536 B ÷ 1.024 = 64 KiB
• 1.048.576 = 2²⁰ → 20 linee
• per 1.000.000: 2¹⁹ = 524.288 non basta, 2²⁰ = 1.048.576 sì → 20 linee, con 1.048.576 − 1.000.000 = 48.576 indirizzi di avanzo
Errore tipico. Scrivere 16 × 2 = 32 (si eleva, non si moltiplica), oppure arrotondare per difetto a 19 linee «perché è più vicino». Se le celle non ci stanno tutte, il bus non serve: si arrotonda sempre per eccesso.
Testo 2. Bus indirizzi a 20 bit, celle da 16 bit: dimensione totale? E quante linee per 512 KiB con celle da 8 bit?
La mossa che sblocca. Sono due numeri indipendenti che si moltiplicano: totale = 2ⁿ × ampiezza della cella. Il bus indirizzi dice quante celle, l'ampiezza dice quanto è larga ciascuna.
celle = 2^20 = 1.048.576
ampiezza = 16 b = 2 B
totale = 1.048.576 x 16 b = 16.777.216 b
= 1.048.576 x 2 B = 2.097.152 B
controllo: 16.777.216 b : 8 = 2.097.152 B coincide
in KiB: 2.097.152 : 1.024 = 2.048 KiB
in MiB: 2.048 : 1.024 = 2 MiB
512 KiB = 512 × 1.024 = 524.288 B; celle da 1 B → 524.288 celle = 2¹⁹ → 19 linee.Errore tipico. Fermarsi a 2²⁰ e rispondere «1 MiB». 2ⁿ conta le celle, non i byte: sono 1 MiB solo se la cella è da un byte.
Esercizio 3 — Decimale contro binario
Testo. Un disco venduto «500 GB»: quanti GiB mostra il sistema operativo? E un file da 2.500.000 B in MB, KiB, MiB?La mossa che sblocca. Non esiste una «conversione fra KB e KiB»: si torna sempre al numero grezzo di byte e poi si divide per il fattore giusto. È lo stesso meccanismo dei prefissi della guida sui sistemi di numerazione, applicato qui a capacità di memoria.
500 GB = 500 x 10^9 = 500.000.000.000 B 1 GiB = 2^30 = 1.073.741.824 B 500.000.000.000 : 1.073.741.824 = 465,66 GiB 465,66 : 500 = 0,9313 -> il 6,87 % in meno 2.500.000 B : 10^6 = 2,5 MB 2.500.000 B : 1.024 = 2.441,40625 KiB 2.500.000 B : 1.048.576 = 2,384 MiBErrore tipico. Dividere 500 per 1,024 una volta sola (viene 488,3) invece che per 1,024³ = 1,073741824. Il fattore va applicato tante volte quanti sono i gradini di prefisso. Secondo errore: concludere che il disco sia difettoso. Terzo errore, ed è quello della sezione 1: dividere una capacità decimale per una binaria senza convertirle prima entrambe in byte.
Esercizi 4 e 5 — Clock, CPI, MIPS
Testo 4. Ciclo di clock a 2,5 GHz? E frequenza di un processore con ciclo da 1,25 ns?T = 1 : (2,5 x 10^9) = 0,4 x 10^-9 s = 0,4 ns = 400 ps f = 1 : (1,25 x 10^-9) = 0,8 x 10^9 Hz = 800 MHz = 0,8 GHz controllo: 800 x 10^6 x 1,25 x 10^-9 = 1 tornaErrore tipico. Rispondere «2,5 ns», cioè ricopiare il numero invece del reciproco. Controllo di verso: più il clock è alto, più il ciclo è corto.
Testo 5. Processore a 3 GHz, CPI medio 4. Istruzioni al secondo, durata media di un'istruzione, tempo per 6 × 10⁹ istruzioni.
Due sigle, sciolte qui perché servono da adesso in poi: IPS sta per istruzioni per secondo, MIPS per milioni di istruzioni per secondo. Sono un tasso, non un tempo.
IPS = 3 x 10^9 : 4 = 7,5 x 10^8 istr/s = 750 MIPS T_istr = 4 x 0,3333 ns = 1,3333 ns T = 6 x 10^9 : 7,5 x 10^8 = 8 s controllo: 6 x 10^9 x 4 x 3,3333 x 10^-10 = 8 sErrore tipico. Moltiplicare per il CPI invece di dividere. Controllo di buon senso: con CPI maggiore di 1 le istruzioni al secondo sono sempre meno degli hertz.
Esercizi 6 e 7 — Le due tracce, da rifare a mano
Sono le tracce della sezione 6. Qui vanno rifatte sul quaderno a colonne chiuse, e poi confrontate. Ricorda la convenzione: una micro-operazione, un ciclo di clock, decodifica compresa.Testo 6. Macchina didattica: parole da 16 bit, bus indirizzi a 12 bit, formato 4 bit di opcode più 12 di indirizzo (0001 = LOAD, 0010 = ADD, 0011 = STORE, 0100 = JMP, 0101 = JZ). PC = 0x010, ACC = 0x0000, Z = 1, C = 0, M[0x010] = 0x10C8, M[0x0C8] = 0x0025. Traccia PC, IR, MAR, MDR, ACC, Z e C.
Prima si decodifica a mano:
0x10C8 = 0001 0000 1100 1000
^^^^ ^^^^^^^^^^^^^^
op indirizzo
opcode 0001 = LOAD
indirizzo 0000 1100 1000 = 0x0C8 = 200 -> LOAD 200
Poi la traccia. Ogni riga mostra lo stato dopo il passo. Ricorda che IR[11..0] sono i dodici bit di destra dell'IR, cioè il campo indirizzo.Passo Micro-operazione PC IR MAR MDR ACC Z C ----- ---------------------- ----- ------ ----- ------ ------ - - 0 stato iniziale 0x010 ---- ---- ---- 0x0000 1 0 1 MAR <- PC 0x010 ---- 0x010 ---- 0x0000 1 0 2 MDR <- M[MAR] 0x010 ---- 0x010 0x10C8 0x0000 1 0 3 PC <- PC + 1 0x011 ---- 0x010 0x10C8 0x0000 1 0 4 IR <- MDR 0x011 0x10C8 0x010 0x10C8 0x0000 1 0 5 decodifica 0001 = LOAD 0x011 0x10C8 0x010 0x10C8 0x0000 1 0 6 MAR <- IR[11..0] 0x011 0x10C8 0x0C8 0x10C8 0x0000 1 0 7 MDR <- M[MAR] 0x011 0x10C8 0x0C8 0x0025 0x0000 1 0 8 ACC <- MDR 0x011 0x10C8 0x0C8 0x0025 0x0025 0 0Fetch = passi 1-4, decode = 5, execute = 6-8. 8 cicli, quindi CPI = 8 per questa istruzione. ACC finale = 0x0025 = 37, e Z passa da 1 a 0.
Errore tipico. Al passo 6 scrivere
MAR <- IR, copiando tutti i 16 bit: nel MAR vanno solo i 12 bit di indirizzo, l'opcode resta all'unità di controllo. E incrementare il PC alla fine invece che al passo 3. Terzo errore: contare cinque passi di fetch perché si è numerato «l'indirizzo esce sul bus e la CU alza READ» come un passo a sé. Non lo è: accade insieme al passo 2, e contarlo porta a 9 cicli invece di 8.Testo 7. Stessa macchina, cinque istruzioni: LOAD 200 (0x10C8), ADD 201 (0x20C9), STORE 202 (0x30CA), JZ 0x016 (0x5016), JMP 0x010 (0x4010), con M[0x0C8] = 0x0025 e M[0x0C9] = 0x000A. Traccia tutto e calcola la durata a 100 MHz.
Il fetch è identico per tutte e cinque, quattro passi: cambia solo l'execute. E i registri non si azzerano fra un'istruzione e l'altra. I punti di controllo:
Passo Micro-operazione PC IR MAR MDR ACC Z C ----- ---------------------- ----- ------ ----- ------ ------ - - 8 ACC <- MDR 0x011 0x10C8 0x0C8 0x0025 0x0025 0 0 16 ACC <- ACC + MDR 0x012 0x20C9 0x0C9 0x000A 0x002F 0 0 23 MDR <- ACC 0x013 0x30CA 0x0CA 0x002F 0x002F 0 0 24 M[MAR] <- MDR 0x013 0x30CA 0x0CA 0x002F 0x002F 0 0 30 Z=0 -> nessun salto 0x014 0x5016 0x013 0x5016 0x002F 0 0 33 PC <- PC + 1 0x015 0x5016 0x014 0x4010 0x002F 0 0 36 PC <- IR[11..0] 0x010 0x4010 0x014 0x4010 0x002F 0 0Verifica dell'aritmetica al passo 16: 0x0025 + 0x000A = 37 + 10 = 47 = 0x002F. Stato finale della memoria: M[0x0CA] = 0x002F. E confronta i passi 33 e 36: il fetch aveva portato il PC a 0x015, il salto ci scrive sopra 0x010. È lì che si vede perché l'incremento sta nel fetch.
prime 3 istruzioni: 24 cicli CPI = 24 : 3 = 8 i due salti: 12 cicli CPI = 12 : 2 = 6 tutto il programma: 36 cicli CPI medio = 36 : 5 = 7,2 T_clock a 100 MHz = 1 : (100 x 10^6) = 10 ns T (3 istruzioni) = 24 x 10 ns = 240 ns T (5 istruzioni) = 36 x 10 ns = 360 nsErrore tipico. Nella STORE scrivere
M[MAR] <- ACC saltando il passo 23: l'accumulatore non è collegato al bus dati, deve passare per il MDR. Attenzione al verso: nella LOAD e nella ADD il MDR si riempie dalla memoria, nella STORE si riempie dalla CPU. E terzo: dare 8 cicli anche ai salti. Un salto non tocca la memoria in fase di esecuzione, quindi costa 6.Esercizio 8 — Tempo medio di accesso con la cache
Testo. Cache con tempo di accesso 2 ns, penalità aggiuntiva di 60 ns in caso di miss, hit rate 95%. Tempo medio? E quale hit rate per scendere a 4 ns?La mossa che sblocca. La penalità qui è aggiuntiva: anche quando si sbaglia, la cache è stata comunque interrogata e quei 2 ns si pagano lo stesso.
miss rate = 1 - 0,95 = 0,05 t_medio = 2 + (0,05 x 60) = 2 + 3 = 5 ns controprova con la media pesata: 0,95 x 2 + 0,05 x 62 = 1,9 + 3,1 = 5 ns coincide 2 + m x 60 <= 4 -> m <= 2 : 60 = 0,03333 hit rate >= 96,67 %Errore tipico, e vale metà esercizio. Scrivere 0,95 × 2 + 0,05 × 60 = 4,9 ns, dimenticando che il miss paga anche i 2 ns della cache. Ma attento: se il testo dicesse «in caso di miss l'accesso richiede 60 ns in tutto», allora 4,9 ns sarebbe la risposta giusta. Prima di calcolare, stabilisci quale delle due convenzioni usa il testo e scrivila sul foglio.
Esercizio 9 — Vince il processore col clock più basso
Testo. Stesso programma di 2 × 10⁹ istruzioni. CPU A: 3,0 GHz, CPI 5. CPU B: 2,4 GHz, CPI 3.A: T_clock = 0,3333 ns 5 x 0,3333 = 1,6667 ns/istr 600 MIPS B: T_clock = 0,4167 ns 3 x 0,4167 = 1,2500 ns/istr 800 MIPS A: 2 x 10^9 : 6,0 x 10^8 = 3,3333 s B: 2 x 10^9 : 8,0 x 10^8 = 2,5000 s rapporto = 3,3333 : 2,5 = 1,3333Vince B, 1,33 volte più veloce, con il clock più basso. Il vantaggio di CPI (5 ÷ 3 = 1,667) supera lo svantaggio di clock (3,0 ÷ 2,4 = 1,25): 1,667 ÷ 1,25 = 1,333.
Errore tipico. Rispondere «A, ha più GHz». E poi l'asimmetria: B impiega il 25% di tempo in meno (0,8333 ÷ 3,3333), A il 33,3% in più. Guadagni e perdite percentuali non si invertono cambiando segno.
Esercizio 10 — Velocità di un bus
Testo. Bus dati largo 32 bit a 200 MHz, un trasferimento per ciclo. Velocità in MB/s, e tempo per 16 MiB.larghezza = 32 b : 8 = 4 B
velocita' = 4 B x 200 x 10^6 = 800 x 10^6 B/s = 800 MB/s
= 800.000.000 : 1.048.576 = 762,94 MiB/s
16 MiB = 16 x 1.048.576 = 16.777.216 B
t = 16.777.216 : 800.000.000 = 0,02097152 s = 20,97 ms
controprova per cicli:
16.777.216 : 4 = 4.194.304 trasferimenti
T_clock = 5 ns -> 4.194.304 x 5 = 20.971.520 ns = 20,97 ms
Errore tipico. Moltiplicare 32 × 200 × 10⁶ e scrivere «6,4 GB/s»: quelli sono bit al secondo, cioè 6,4 Gb/s = 800 MB/s. Il fattore 8 è l'errore numero uno della materia. Secondo errore: dividere 16 MiB per 800 MB/s mescolando le due unità.Esercizio 11 — Perché alzare solo il clock non basta
Testo. Un programma dura 100 s: 60 s di calcolo nella CPU, 40 s di attese di memoria e I/O che non dipendono dal clock. Raddoppiando il clock? Quadruplicandolo? E il massimo teorico?La mossa che sblocca. Si accelera solo la parte accelerabile:
T_nuovo = T_accelerabile / k + T_fisso. È la legge di Amdahl in versione aritmetica.k = 2 -> 60 : 2 + 40 = 70 s speedup = 100 : 70 = 1,43 k = 4 -> 60 : 4 + 40 = 55 s speedup = 100 : 55 = 1,82 k -> inf -> 0 + 40 = 40 s speedup = 100 : 40 = 2,5Raddoppiando ancora il clock, da 2× a 4×, il tempo scende solo da 70 a 55 secondi. E anche con un processore infinitamente veloce il programma non scenderà mai sotto i 40 s. È questo il conto promesso in fondo alla sezione 4.
Errore tipico. Applicare il fattore a tutto il tempo (100 ÷ 2 = 50 s). Ed è precisamente il ragionamento con cui si compra la CPU più costosa e non si vede alcuna differenza. Morale: se il 40% del tempo è attesa di memoria, si investe in cache e in bus, non in megahertz.
Esercizio 12 — Riconoscere i blocchi dallo schema
Testo. Assegna a ogni lettera il nome corretto, giustificando con l'indizio dello schema, non con la memoria. Poi: quanto vale in KiB la memoria (J)? E che cosa manca del tutto?DENTRO LA CPU FUORI ------------------------------------------- ---------------------- (A) ------------> (F) (J) 4096 celle x 16 bit (G) ------------> (B) (G) <-----------> (D) (G) ------------> (C) (B) ------------> (E) (D) <-----------> (C) (E) ------------> tutti gli altri (F) ====(H) 12 linee, un verso solo=====> (J) (G) <===(I) 16 linee, doppio verso======> (J)Indizi: (A) contiene 0x0012 e aumenta di 1 dopo ogni prelievo. (B) contiene 0x20C9, una parola intera, e i suoi primi 4 bit vanno a (E). (C) esegue +, −, AND, OR e produce i flag Z e C. (D) contiene 0x002F ed è l'unico registro collegato in entrambi i versi a (C) — a (C) arriva anche (G), ma in un verso solo. (E) riceve i primi 4 bit di (B) ed emette segnali verso tutti gli altri. (F) e (G) sono gli unici registri affacciati fuori dalla CPU.
| Lettera | Nome | Indizio decisivo |
|---|---|---|
| (A) | PC, contatore di programma | contiene un indirizzo, si incrementa da solo a ogni fetch, e alimenta (F) |
| (B) | IR, registro istruzione | riceve la parola-istruzione intera da (G) e la spezza in opcode più indirizzo |
| (C) | ALU | esegue le operazioni e genera i flag |
| (D) | Accumulatore | unico registro dati legato all'ALU nei due versi |
| (E) | Unità di controllo | legge l'opcode e pilota tutti gli altri |
| (F) | MAR | affacciato su un fascio unidirezionale di 12 linee, alimentato da (A) |
| (G) | MDR | affacciato sul fascio bidirezionale largo quanto la cella, e alimenta (B) |
| (H) | Bus indirizzi | 12 linee, un solo verso: CPU verso memoria |
| (I) | Bus dati | 16 linee, doppio verso: lettura e scrittura |
| (J) | Memoria centrale | matrice di celle indirizzabili |
Le due frecce che nello schema fanno tutto il lavoro sono (A) → (F) e (G) → (B), e conviene rileggerle accanto alla traccia della sezione 6: sono i passi 1 e 4 del fetch. Il PC non alimenta mai direttamente l'IR — se in uno schema trovi una freccia dal contatore di programma al registro istruzione, quello schema descrive una macchina che nella sezione 6 non esiste.
Le altre tre servono a eseguire, e sono la prova che lo schema e la traccia sono la stessa macchina.
(G) → (D) è il passo 8, ACC ← MDR della LOAD. (G) → (C) è il passo 16, ACC ← ACC + MDR: l'ALU prende un operando dall'accumulatore e l'altro dal MDR, e per questo la freccia verso (C) esiste ma in un verso solo. (D) → (G) è il passo 23, MDR ← ACC della STORE. E qui si vede a occhio la cosa che la sezione 6 diceva a parole: fra (D) e (J) non c'è nessuna freccia diretta. L'accumulatore non tocca il bus dati; ci arriva passando per il MDR, che è esattamente il motivo per cui il passo 23 non si può saltare.Perché (F) è il MAR e non il MDR: si affaccia su 12 linee unidirezionali, tante quante ne servono per 2¹² = 4.096 celle. Il registro dati dovrebbe essere largo 16 bit come la cella, e bidirezionale. Regola generale: il MAR è largo quanto il bus indirizzi, il MDR è largo quanto la cella.
4.096 celle x 16 b = 65.536 b 65.536 b : 8 = 8.192 B 8.192 B : 1.024 = 8 KiBChe cosa manca: il bus di controllo (READ, WRITE, clock, interrupt) e tutto l'ingresso/uscita. Senza le linee di controllo i passi
MDR <- M[MAR] e M[MAR] <- MDR dell'esercizio 7 avrebbero indirizzo e dato identici come struttura, e sarebbero indistinguibili.Errore tipico. Rispondere «4.096 B = 4 KiB» leggendo solo il numero di celle e dimenticando che ogni cella vale 2 byte. E chiamare «memoria» i registri (A), (B), (D): lo sono in senso lato, ma non hanno un indirizzo — si raggiungono per nome dentro l'unità di controllo, non mettendo un numero sul bus.
Gli errori che ti costano il voto
Dieci errori, ciascuno smontato in quattro mosse: come lo pensano quasi tutti → perché sembra giusto → cosa succede davvero → come te ne accorgi.
1. Il bus fra le parti del modello di von Neumann. Quasi tutti: CPU, memoria, bus, ingresso, uscita. Sembra giusto: senza bus i pezzi non comunicano, e ogni schema di libro lo disegna. Davvero: il First Draft of a Report on the EDVAC (30 giugno 1945) non nomina mai il bus, e non usa nemmeno l'espressione «architettura di von Neumann». Il bus è un'astrazione successiva. Te ne accorgi: se nel tuo elenco ci sono sei voci, una è di troppo.
2. Contare R fra le cinque parti. Quasi tutti: l'outside recording medium R viene messo in fila con le altre. Sembra giusto: compare nello stesso paragrafo del rapporto, il § 2.6. Davvero: le parti numerate sono cinque — CA, CC, M, I, O — e von Neumann tiene R esplicitamente fuori dal dispositivo. Te ne accorgi: R è dove i dati stanno quando la macchina è spenta, non un organo della macchina.
3. «Von Neumann inventò il programma memorizzato». Quasi tutti: c'è il suo nome sull'architettura, quindi è sua l'idea. Sembra giusto: il documento porta solo la sua firma. Davvero: scrisse il testo, ma la Moore School ci lavorava da circa sette mesi prima che lui arrivasse, e la paternità delle idee è contesa; un tribunale federale si è espresso sui fatti nel 1973. Te ne accorgi: la formulazione prudente — «il rapporto che porta il suo nome descrive» — non è mai sbagliata.
4. Attribuire a Backus il memory wall. Quasi tutti: «collo di bottiglia» viene letto come «la RAM è lenta rispetto alla CPU». Sembra giusto: oggi è vero, ed è il problema che tutti conoscono. Davvero: Backus parlava nel 1977, quando il divario di velocità era modesto, e il suo era un limite concettuale e linguistico — il pensiero una parola per volta. Il memory wall è un problema degli anni Novanta in poi. Te ne accorgi: se la tua spiegazione del collo di bottiglia non nomina il modo di programmare, hai raccontato un'altra cosa.
5. MAR e MDR confusi, o MDR e MBR trattati come registri diversi. Quasi tutti: nei disegni stanno affiancati e finiscono nella stessa casella mentale. Sembra giusto: sono entrambi l'interfaccia verso la memoria. Davvero: il MAR dice dove, il MDR porta cosa; e MDR e MBR sono due nomi della stessa cosa, non due registri. Te ne accorgi: conta le linee. Il MAR è largo quanto il bus indirizzi, il MDR quanto la cella.
6. PC incrementato alla fine del ciclo. Quasi tutti: «finita l'istruzione, avanti alla prossima». Sembra giusto: è l'ordine cronologico intuitivo. Davvero: il PC si incrementa durante il fetch, al passo 3, subito dopo che l'indirizzo è stato usato. Solo così un'istruzione di salto, in fase di esecuzione, può sovrascrivere il valore appena incrementato — ed è quello che succede al passo 36 della traccia della sezione 6. Te ne accorgi: con l'incremento in fondo, ogni salto verrebbe annullato un attimo dopo. Se non sai spiegare come funziona un JMP, l'errore è questo.
7. «Un processore a 64 bit indirizza 2⁶⁴ byte». Quasi tutti: 64 bit di registro, 64 bit di indirizzo. Sembra giusto: è il numero stampato sulla scatola. Davvero: l'x86-64 impone la forma canonica e implementa 48 bit, cioè 256 TiB, che diventano 57 bit e 128 PiB con la paginazione a cinque livelli. Te ne accorgi: l'architettura dichiara 64 bit, l'hardware ne cabla molti meno.
8. La cache L1 presentata come unica. Quasi tutti: un blocco solo, etichettato L1. Sembra giusto: i livelli si contano 1, 2, 3. Davvero: nei processori reali la L1 è separata in L1i (istruzioni) e L1d (dati), come nelle tabelle della sezione 7, ed è esattamente il punto in cui l'architettura Harvard entra nei PC. Te ne accorgi: è la risposta alla domanda «e allora il mio PC è von Neumann o Harvard?».
9. Usare i valori SSD di Jeff Dean come attuali. Quasi tutti: si cita la tabella Latency Numbers Every Programmer Should Know e si scrive 150 µs per una lettura casuale da SSD. Sembra giusto: è la tabella più diffusa del mestiere. Davvero: i valori di memoria di massa risalgono a circa il 2012; gli NVMe attuali stanno a 20-70 µs, un ordine di grandezza meno. I valori per cache e RAM invece reggono. Te ne accorgi: se citi quella tabella, cita anche la data.
10. L'accumulatore dato per il registro operativo delle CPU moderne. Quasi tutti: «la CPU mette il risultato nell'accumulatore». Sembra giusto: è così in tutti i modelli didattici, compreso quello dell'esercizio 12. Davvero: i processori reali hanno banchi di registri generali — 16 su x86-64, 32 su AVR. Te ne accorgi: l'accumulatore singolo è il modello su cui si impara il ciclo macchina, non una descrizione dell'hardware di oggi. Dirlo per intero non costa niente e vale mezzo voto.
I tre errori di conto che tornano in ogni verifica
Bit e byte, fattore 8. 100 Mbit/s = 100.000.000 ÷ 8 = 12,5 MB/s. La «fibra da 1 Giga» dà 125 MB/s, quindi un gioco da 5 GB si scarica in 5.000 ÷ 125 = 40 secondi nel caso ideale, non in 5. E chi converte bit in byte dividendo per 1.024 invece che per 8 sbaglia di 128 volte.Decimale contro binario. Lo scarto cresce con l'ordine di grandezza: +2,4% sui kilo, +4,9% sui mega, +7,4% sui giga, +10,0% sui tera. La regola operativa: massa e rete → decimale, RAM e indirizzamento → binario — ed è la regola che rimette a posto il conto della sezione 1, dove 500 GB di disco contro 8 GiB di RAM fanno 58 volte e non 62,5. Il caso diagnostico perfetto è il floppy da 1,44 MB, che vale 1.474.560 byte, cioè 1.440 KiB: non rispetta né l'una né l'altra convenzione, e serve proprio a farti capire che le convenzioni sono tre. La costruzione dei prefissi, se vuoi rivederla, sta nella guida sui sistemi di numerazione: binario, decimale, esadecimale; qui la applichiamo soltanto.
Cache della CPU contro cache del browser. 32 KiB contro 500 MB fanno 500.000.000 ÷ 32.768 = oltre 15.000 volte; 1 ns contro i 20-70 µs di un NVMe attuale fanno da 20.000 a 70.000 volte. Se usi il vecchio 150 µs della tabella di Jeff Dean ti viene 150.000, ma è lo stesso numero che l'errore 9 di questa sezione dichiara superato: o lo aggiorni, o dichiari che stai parlando di un disco meccanico. E soprattutto: la cache della CPU non è una cartella e non si svuota da un'interfaccia utente, è gestita in automatico dall'hardware. Istruzioni macchina per invalidarla esistono — su x86 sono
CLFLUSH e WBINVD, su ARM le operazioni di data cache clean and invalidate — ma le usano il sistema operativo e i driver, per esempio quando una periferica scrive in memoria per conto suo, non tu da un menu.E l'errore sui core, che produce una previsione falsificabile
I core non sono CPU indipendenti: condividono la L3, il controller di memoria e l'interconnessione. La legge di Amdahl mette i numeri:Speedup = 1 : (1 - p + p/s) p = 0,95 s -> infinito -> 20 x (non 100, non 1000) p = 0,90 s = 8 -> 4,7 x p = 0,90 s = 16 -> 6,4 x -> raddoppiare i core rende +36 %E 8 core con SMT (simultaneous multithreading, l'esecuzione di due flussi di istruzioni sullo stesso core) si presentano al sistema operativo come 16 processori logici, ma le risorse di esecuzione restano una serie per core: i due thread se le prestano quando uno è in stallo. Un dual-core con SMT è meno potente di un vero quad-core, pur mostrando lo stesso numero nel Task Manager.
Perché queste convinzioni sono così dure a morire
Vale la pena dirtelo, perché non è colpa tua. In architettura, un modello mentale sbagliato non produce quasi mai un fallimento visibile. Se credi che il programma stia dentro la CPU non succede niente: il computer continua ad accendersi e a funzionare. Manca il ciclo di retroazione che nelle altre materie erode le idee sbagliate — è l'implicazione della tesi di Ben-Ari (Constructivism in Computer Science Education, SIGCSE 1998): lo studente principiante non possiede un modello efficace del computer, quindi il modello va insegnato, non presupposto. È l'opposto di quello che ti succede con l'algebra di Boole e le porte logiche, dove la tavola di verità è un tribunale d'appello che ti smentisce in quattro righe.E poi c'è la seconda ragione: sono tutte la stessa convinzione. La memoria come contenitore, il software come sostanza immagazzinata dentro quel contenitore, la velocità come quantità che si accumula, il core come oggetto autonomo. Ecco perché correggerle una alla volta non funziona: cambi il contenitore e conservi lo schema.
La regola d'oro degli esercizi
Dichiara sempre la convenzione (1.000, 1.024, o l'ibrida del floppy se ti capita). Sempre l'ampiezza della cella (per il bus indirizzi). Sempre il CPI (per il tempo di esecuzione), e con lui che cosa conta come un ciclo. La maggior parte degli «errori dello studente» in questi ambiti sono, in realtà, esercizi mal posti — e scrivere la convenzione in cima al foglio è il modo più economico di non pagarli tu.Domande frequenti
Il mio telefono dice 8 GB di RAM e 256 GB di ROM, ma il libro dice che la ROM è una memoria di sola lettura: chi sbaglia?
Sbaglia il volantino del negozio. I 256 GB del telefono sono memoria di massa riscrivibile: ci salvi le foto ogni giorno, quindi di "sola lettura" non hanno niente. La ROM vera è un'altra cosa: piccola, non volatile, non riscrivibile dall'utente, e soprattutto non ci si salvano file, perché non ospita un file system: contiene il codice di avvio della macchina. È per questo che alla domanda "la ROM è una memoria di massa?" si risponde no. Il marketing ha preso la sigla ROM e l'ha usata per dire "memoria interna", e ormai la trovi così su tutte le schede tecniche. Per la verifica tieni tre caselle separate: RAM = memoria centrale volatile e veloce; ROM = non volatile e di sola lettura; memoria interna del telefono = memoria di massa, come un SSD.
Ma allora il programma sta dentro la CPU?
No, e a dimostrarlo è il ciclo macchina stesso: il program counter contiene l'indirizzo della prossima istruzione, non l'istruzione. La CPU va a prendersela in memoria una alla volta, ed è la fase di fetch — che non esisterebbe affatto se il programma fosse già dentro. Attenzione però a non correggere troppo: un po' di memoria nella CPU c'è davvero, sono i registri e le cache. Solo che è pochissima. I registri general purpose di un x86-64 sono 16 da 64 bit, cioè 128 byte in tutto: rispetto a un programma da 1 MB, cioè 1.000.000 di byte, sono 128 diviso 1.000.000, lo 0,0128%. Tutto il resto è in RAM.
Quali sono le parti dell'architettura di von Neumann? Il mio libro ne elenca cinque, un altro sei.
Nel rapporto del 1945 le parti specifiche sono cinque, numerate una per una con un ordinale: CA (parte aritmetica centrale, quella che oggi chiami ALU) nel § 2.2, CC (controllo centrale) nel § 2.3, M (memoria) nei §§ 2.4-2.5, I (input) nel § 2.7, O (output) nel § 2.8. CA e CC insieme formano C nel § 2.6, ed è da lì che nasce la nozione moderna di CPU: la CPU non è una delle cinque parti, è la somma delle prime due. Chi ne conta sei di solito aggiunge R, il supporto esterno di registrazione: von Neumann lo introduce nello stesso § 2.6, ma lo tiene esplicitamente fuori dalle cinque parti, perché sta fuori dal dispositivo. E chi mette il bus nell'elenco sbaglia proprio storia: nel rapporto la parola bus non compare mai, è un'astrazione arrivata dopo.
Il mio PC è di von Neumann o è Harvard?
Tutti e due, a due livelli diversi. Von Neumann vuol dire una memoria sola per istruzioni e dati, con un bus solo; Harvard vuol dire due memorie fisicamente separate, due bus, e anche larghezze libere su ciascun lato: in un AVR a 8 bit i dati stanno su 8 bit e le istruzioni su 16, e l'istruzione arriva in un colpo solo. In una memoria unica quell'istruzione non è impossibile, si spalma su più celle: costa solo più accessi. Il tuo PC ha un unico spazio di indirizzamento, quindi verso il programma è von Neumann; ma dentro il processore la cache di primo livello è divisa in L1i (istruzioni) e L1d (dati), e quello è Harvard. Si dice Harvard modificata. Harvard pura la trovi nei microcontrollori, non nei PC.
Il program counter si incrementa all'inizio o alla fine dell'istruzione?
Durante il fetch, subito dopo che il suo valore è stato usato per interrogare la memoria — non alla fine del ciclo. Sembra un dettaglio e invece decide tutto: se l'istruzione in esecuzione è un salto, quel salto scrive un nuovo indirizzo nel PC, e un incremento successivo cancellerebbe la destinazione. Il fetch è di quattro micro-operazioni, non cinque: MAR ← PC, MDR ← memoria, PC ← PC + 1, IR ← MDR, e solo dopo decodifica ed esecuzione. Il segnale READ sul bus di controllo non è un passo in più, accade insieme alla lettura. Il "+1" vale nel modello didattico con istruzioni tutte della stessa ampiezza; nelle macchine vere si somma la lunghezza dell'istruzione appena prelevata.
Che differenza c'è fra MAR e MDR? E l'MBR cos'è ancora?
MAR e MDR non sono sinonimi: sono i due lati della stessa conversazione con la memoria. Il MAR (memory address register) dice dove, ed è largo quanto il bus indirizzi; il MDR (memory data register) porta cosa, ed è largo quanto la cella. Se in uno schema li vedi affiancati con larghezze diverse, per esempio 12 linee e 16, il numero di linee ti dice al volo chi è chi. L'MBR (memory buffer register) invece è soltanto un altro nome dell'MDR: stessa identica cosa, due sigle, e i libri usano l'una o l'altra senza avvisarti.
Un processore da 3 GHz esegue tre miliardi di istruzioni al secondo?
No: il clock conta i cicli, non le istruzioni. Il tempo di un programma è un prodotto di tre fattori — numero di istruzioni × CPI × durata del ciclo — e la frequenza tocca solo l'ultimo. Il CPI, cioè i cicli per istruzione, dipende anche dal miscuglio di istruzioni: nella macchina didattica di questa guida una LOAD costa 8 cicli e un salto ne costa 6. Con CPI 4, un processore a 3 GHz esegue 750 milioni di istruzioni al secondo, non tre miliardi. E il confronto fra due macchine si ribalta facilmente: A a 3,0 GHz con CPI 5 fa 600 MIPS, B a 2,4 GHz con CPI 3 ne fa 800. Vince B, quello con il clock più basso. Il caso storico è del 18 luglio 2001, quando Apple mostrò dal palco del Macworld Expo un G4 a 867 MHz completare in 45 secondi un lavoro che a un Pentium 4 da 1,7 GHz ne costava 82.
Un processore a 64 bit può indirizzare 2⁶⁴ byte di memoria?
No, e non lo fa nessun processore esistente. La regola vera è che con n linee di bus indirizzi si indirizzano 2ⁿ celle, e le linee davvero cablate sono molte meno di 64: l'x86-64 ne implementa 48, cioè 281.474.976.710.656 indirizzi, 256 TiB (57 bit e 128 PiB con la paginazione a cinque livelli). Attenzione al passaggio da celle a byte: 2ⁿ conta le celle, e coincide con i byte solo se la cella è da un byte. Il conto 2ⁿ però è esatto e spiega la storia: l'Intel 8086 del 1978 aveva 20 linee di indirizzo e celle da un byte, quindi 2²⁰ = 1.048.576 byte = 1 MiB. Il famigerato tetto di memoria del DOS era soltanto la larghezza di un bus.
La memoria cache è quella che si svuota dal browser?
Il principio è lo stesso — tenere una copia vicina per non andare a prendere le cose lontano — ma sono due oggetti separati da cinque ordini di grandezza. La cache della CPU è SRAM sul chip del processore: 32-64 KiB di L1 per core, letti in circa 1 nanosecondo, cioè 4-5 cicli di clock. La cache del browser sono file su disco: centinaia di MB, letti in decine di microsecondi. E soprattutto la cache della CPU non è una cartella e non si svuota da un'interfaccia utente: non ha un percorso, non ha un pulsante, è gestita in automatico dall'hardware. Istruzioni macchina per invalidarla esistono, su x86 sono CLFLUSH e WBINVD, ma le usano il sistema operativo e i driver per la coerenza con le periferiche, non tu.
Devo sapere il binario e le porte logiche prima di studiare l'architettura?
Sì, e questa guida li dà per fatti. Il binario e l'esadecimale ti servono per leggere gli indirizzi e il contenuto delle celle, e stanno nella guida sui sistemi di numerazione. Le porte AND, OR e NOT sono il materiale con cui è costruita l'ALU, e stanno nella guida sull'algebra di Boole — che però, va detto, non è prescritta da nessuno dei documenti ministeriali citati in questa guida: è un prerequisito didattico reale, non un obbligo di programma. I diagrammi di flusso stanno nella guida sugli algoritmi: qui vedi la macchina che quei diagrammi li esegue per davvero, e il rombo di decisione diventa un salto condizionato che scrive nel program counter. Una sorpresa: nelle Linee guida dei tecnici, fra le Conoscenze di Tecnologie informatiche, la codifica dei dati è elencata prima dell'architettura, mentre il concetto di algoritmo viene dopo.
Fonti: J. von Neumann, First Draft of a Report on the EDVAC, 30 giugno 1945, edizione critica a cura di M. D. Godfrey, IEEE Annals of the History of Computing, vol. 15, n. 4, 1993, pp. 27-75 · J. Backus, Can Programming Be Liberated from the von Neumann Style?, Communications of the ACM, vol. 21, n. 8, agosto 1978, pp. 613-641 · W. S. McCulloch, W. Pitts, A logical calculus of the ideas immanent in nervous activity, Bulletin of Mathematical Biophysics, vol. 5, 1943, pp. 115-133 · Indicazioni nazionali per il curricolo della scuola dell'infanzia e del primo ciclo, Allegato al DM 9 dicembre 2025 n. 221 · Indicazioni nazionali per i licei, Allegato F al DM 7 ottobre 2010 n. 211 · Direttiva MIUR n. 57 del 15 luglio 2010, Allegato A.2 · brevetto USA 3.120.606 e sentenza Honeywell v. Sperry Rand, 19 ottobre 1973 · datasheet Microchip/Atmel ATmega32 e ATmega128
Utenti più affidabili
Ancora nessuno in classifica. Rispondi a una domanda e ci finisci tu.
Ultimi articoli
- Fisica La termodinamica: dove finisce l'energia che sparisce
- Scienze Le leggi di Mendel: genetica e quadrato di Punnett
- Scienze Gli enzimi: che cosa sono e come fanno quello che fanno
- Informatica Le reti e Internet: come viaggiano i dati, dal tasto Invio al pixel
- Storia Il Congresso di Vienna e la Restaurazione: come andarono davvero le cose
- Scienze La cellula: procarioti ed eucarioti, membrana, organuli e 43 esercizi svolti
- Fisica Forze ed equilibrio: vettori, attrito, piano inclinato, momento e leve
- Informatica Architettura del computer: von Neumann, CPU, memorie e ciclo macchina
Ultimi commenti
Ancora nessun commento. Se leggi qualcosa che non ti torna, scrivilo tu per primo.

0 commenti
Nessun commento. Se qualcosa non ti torna o vuoi aggiungere un pezzo, scrivi tu il primo.
Vuoi commentare? Serve un account: si fa in trenta secondi e non chiediamo conferme via email.
Crea un account Ho già un account