Lingue disponibili:

Programmare come se fosse il 1982. Parte II – Il Processore

Nella Parte I abbiamo coperto il panorama: l’epoca, la macchina, il contesto. Ora è il momento di scendere di un livello e capire come funziona davvero il processore. Dove vivono i dati, come vengono lette le istruzioni e cosa accade ogni frazione di secondo mentre un programma è in esecuzione.

Registri: lo spazio di lavoro del processore

Quando scrivi qualcosa come x = 5 + 3 in qualsiasi linguaggio moderno, il processore deve prendere il 5 da qualche parte, prendere il 3 da qualche parte, sommarli e salvare il risultato. Quel “qualche parte” sono i registri.

Un registro è uno spazio di archiviazione che vive all’interno del processore stesso. La RAM è un enorme magazzino all’esterno. Il processore deve fare un viaggio fin là per recuperare qualsiasi cosa. Un registro è la tasca del processore: minuscola, ma istantanea.

Diagramma del processore e della RAM

Ogni operazione aritmetica o logica avviene all’interno dei registri. La RAM è semplicemente dove metti le cose quando non le stai usando attivamente.

Il MOS 6510 del Commodore 64 aveva esattamente tre registri di uso generale:

A, l’Accumulatore. Il registro principale. Praticamente ogni operazione passa attraverso di lui: addizioni, sottrazioni, operazioni logiche, lettura e scrittura in memoria. Il nome viene dall’accumulare risultati. Se il 6510 fosse una cucina, l’A sarebbe il tagliere. Tutto passa da lì prima o poi.

X e Y, i Registri Indice. Funzionano come contatori e puntatori di posizione. Il nome viene da indice, come l’indice di un array. La i di un ciclo for in Python? Era esattamente questo il ruolo dell’X o dell’Y in assembly. Li usavi per scorrere liste, navigare nella memoria, contare iterazioni.

Tre registri è pochissimo, e era intenzionale. Nel 1975, quando il 6502 fu progettato, ogni registro costava transistor, e i transistor costavano denaro e spazio fisico sul chip. La mentalità ingegneristica dell’epoca era fare di più con meno. In pratica, questo significava che il programmatore doveva pianificare con attenzione quale registro avrebbe contenuto quale dato, e salvare temporaneamente i valori nella RAM ogni volta che tutti e tre erano occupati. Era come programmare con solo tre variabili disponibili in qualsiasi momento.

Il ciclo di esecuzione: come il processore legge un programma

Ecco qualcosa che cambia per sempre il modo in cui vedi un programma: per il processore, non esiste distinzione tra codice e dato. Tutto in memoria sono byte. Ciò che rende un byte un’istruzione è semplicemente il fatto che il processore stia puntando a esso nel momento giusto.

Il processore funziona in un ciclo eterno e molto semplice:

1. Leggi il byte all'indirizzo a cui punta il PC
2. Interpreta quel byte come un'istruzione
3. Esegui l'istruzione
4. Avanza il PC
5. Ripeti

Il PC qui è il Program Counter, un registro speciale che non conserva dati del programma ma l’indirizzo della prossima istruzione da eseguire. Il suo unico compito è dire al processore dove si trova nella mappa della memoria. È il cursore di esecuzione.

Questo ciclo non si ferma mai. Finché il C64 è acceso, il 6510 sta ripetendo questo loop milioni di volte al secondo, leggendo un byte, eseguendo, avanzando, leggendo il successivo. Nessuno scheduler, nessun sistema operativo che gestisce nulla di tutto questo. Solo il processore in modalità automatica, senza pausa.

Quando un programma andava in crash sul C64, quello che di solito accadeva è che il PC finiva per puntare a un indirizzo contenente dati casuali, e il processore cercava di interpretare quei byte come istruzioni valide. Il risultato era imprevedibile: a volte lo schermo si bloccava, a volte appariva spazzatura, a volte la macchina si riavviava. Non c’era nessuna rete di sicurezza. Proprio nessuna.

Registri speciali

Oltre ad A, X e Y, il 6510 aveva altri tre registri che non conservano dati del programma ma controllano il funzionamento del processore stesso:

Il PC (Program Counter) lo abbiamo già visto: punta alla prossima istruzione.

Lo SP (Stack Pointer) punta in cima allo stack, una regione speciale della memoria usata per salvare gli indirizzi di ritorno quando il programma chiama una subroutine. Quando salti in una routine e torni indietro, è lo SP a ricordare dove eri prima della chiamata.

Lo SR (Status Register) è diverso da tutti gli altri: invece di conservare un numero, tiene 8 bit indipendenti chiamati flag, ognuno con un significato specifico. Un flag si attiva quando il risultato di un’operazione è zero. Un altro quando il risultato è negativo. Un altro quando un’addizione ha superato il limite di un singolo byte. Questi flag sono il fondamento di ogni decisione che un programma prende: gli if, i cicli, i confronti. Approfondiremo tutto questo nella Parte IV.

Registri di uso generale:    A   X   Y
Registri di controllo:       PC  SP  SR

Nel prossimo post usciamo dal processore e guardiamo quello che lo circonda: la RAM, come è organizzata in indirizzi, cosa sia realmente l’esadecimale e perché certe regioni della memoria valevano il loro peso in oro.