Corso di informatica - Architettura di un computer


Nel più semplice schema che possiamo immaginare un computer può essere scomposto nei seguenti componenti: CPU, RAM, BIOS, I/O.

 

 

Per avere un'idea un pò più precisa di quello che succede nella CPU quando gira un programma, si faccia riferimento a questa figura.

 

 

Si individuano due componenti principali: l'unità di controllo e la ALU (Arithmetic Logical Unit). L'unità di controllo è la parte che legge le istruzioni dalla RAM e le esegue.

Essa è dotata di due registri di memoria che chiamiamo registro indirizzo e registro istruzione. Ogni registro non è altro che una parola analoga a quelle che costituiscono la RAM eccetto che per una velocità di accesso maggiore. I registri di memoria sono composti da un numero di bits che dipende dall'architettura del computer. In realtà di registri ce ne sono molti nella CPU ma a questo livello di descrizione ci possiamo limitare al registro indirizzo ed al registro istruzione. L'altro componente della CPU che evidenziamo è la ALU la quale esegue tutte le operazioni aritmetiche e logiche. Anche nella ALU possiamo riconoscere due registri principali che possiamo chiamare registro A e registro B. Questi due registri sono impiegati per memorizzare gli operandi ed anche per ospitare i risultati delle operazioni.

La figura mostra come la CPU sia una macchina periodica che esegue la stessa serie di operazioni in ogni periodo, detto ciclo di CPU. Il ciclo di CPU è dato dal tempo trascorso tra un impulso dell'orologio del computer, detto clock e quello successivo. In una prima approssimazione possiamo dire che in un ciclo la CPU esegue un'istruzione. La realtà tecnologica è poi più complessa: vi sono istruzioni che richiedono più di un ciclo per essere eseguite e vi sono CPU più recenti che in un solo ciclo sono in grado di compiere il lavoro di più istruzioni. Questo fa anche capire perché il semplice confronto fra i clock di due CPU non sia completamente descrittivo della reale velocità di esecuzione perché una delle due CPU può eseguire più operazioni in uno stesso ciclo e quindi può risultare più veloce anche se ha un clock più lento. Questo è per esempio il caso delle CPU prodotte dalla AMD che fanno più lavoro in un ciclo rispetto alle CPU della Intel per cui, per certe operazioni, una CPU AMD può essere più veloce di una CPU Intel, anche se ha un clock più lento. Tuttavia, al fine della comprensione di base del funzionamento della CPU la corrispondenza fra cicli ed istruzioni può essere tranquillamente accettata.

 

In ogni caso, data uno specifico computer, la quantità di cose che questo riuscirà a fare in un singolo ciclo di CPU sarà fissa e limitata. Questo è in apparente contraddizione con il fatto che siamo abituati a vedere computer sui quali girano molti programmi per volta. A nessun utente risulta infatti che vi sia un limite fisso alla quantità di programmi diversi che può lanciare. Come si spiega questo fatto?

 

Il trucco sta in quello che viene chiamato time slicing, si potrebbe dire spezzettamento temporale. Con questo meccanismo il sistema operativo divide il tempo in intervalli regolari dell'ordine di qualche decina di millisecondi. In ciascuno di questi intervalli gira un solo programma per volta. Finito l'intervallo di tempo, il sistema pone il programma che girava in uno stato di quiescenza e fa partire l'esecuzione di un altro programma che è in attesa affinché possa essere operativo per tutto il prossimo intervallo di tempo. La lista dei programmi in attesa può essere anche molto lunga. Il sistema sceglie il prossimo in base a vari criteri fra cui l'ordine con il quale i programmi hanno richiesto di essere eseguiti ma anche in base ad una priorità che viene assegnata a ciascun programma al momento del suo lancio. Questo perché vi sono programmi che sono critici per il funzionamento del sistema ed altri che sono meno critici. In tal caso, a parità di altre condizioni, un programma a priorità più elevata avrà la precedenza rispetto ad uno con priorità inferiore.

 

Facciamo un esempio. Tutto quello che avviene in un computer è di fatto realizzato mediante un pezzo di software, un programma per l'appunto. Il movimento del puntatore sullo schermo, manovrato dal mouse, è gestito da un programma che traduce in coordinate sullo schermo i segnali provenienti dal mouse. È chiaro che questo programma deve avere priorità molto elevata perché la possibilità che l'utente possa intervenire non deve essere inficiata da altre attività del computer. In altre parole, questo si traduce nel fatto che, se il programma che gestisce il mouse non riesce a funzionare a causa di altri programmi, voi vedete il puntatore inchiodato sullo schermo che non risponde più ai movimenti del mouse, cioè il computer sembra "inchiodato".

 

Poiché gli intervalli di tempo sono molto piccoli rispetto alla nostra capacità di percezione, succede che a noi sembri che le varie applicazioni funzionino simultaneamente in modo fluido. Nella realtà ogni applicazioni va avanti a "scatti" operando di fatto solo all'interno degli intervalli di tempo consentiti. È chiaro che se i programmi sono molti, ogni applicazione dovrà attendere un tempo superiore prima che le ricapiti l'intervallo a lei dedicato ed il rischio è quello che l'utente inizi a percepire l'effetto del time-slicing. Può addirittura succedere che il sistema sembri inchiodato mentre è solo diventato molto lento.

 

Importante: Da queste considerazioni scaturisce un'osservazione importante. Non è una buona idea aprire molte applicazioni senza che ve ne sia la necessità. Rischiate di peggiorare le performance del computer e, in certi casi, di bloccarlo, magari anche solo apparentemente. La cosa fa poca differenza perché se voi avete deciso che è bloccato lo farete probabilmente ripartire da zero col rischio di buttare via lavoro fatto ma anche di creare una condizione di incongrenza nel sistema che vi potrebbe danneggiare in seguito. I sistemi Windows in particolare non avrebbero bisogno del vostro "aiuto" per cacciarsi in situazioni instabili ... ;)

 

Con il termine istruzione ci riferiamo qui a quelle che fanno parte del linguaggio macchina. Tali istruzioni sono codificate in 0 ed 1 che l'unità è in grado di decodificare. A queste istruzioni, corrispondono dei codici mnemonici che facilitano il compito dei programmatori. Il linguaggio di programmazione che si avvale di questi codici prende il nome di assembler. Il linguaggio assembler è specifico di un computer perché è strettamente associato all'architettura di quel computer. In questo è diverso dai linguaggi di programmazione di livello elevato che presentano un livello di astrazione maggiore e che sono quindi svincolati dall'architettura di uno specifico computer.

 

Facciamo qui un esempio semplicissimo di un linguaggio assembler per un ipotetico computer basato su di un'architettura a soli 8 bits. È evidente che tale esempio ha valore puramente didattico. Nella seguente tabella riportiamo i valori numerici che contraddistinguono le singole istruzioni insieme ai corrispondenti codici mnemonici. L'istruzione che sta in 8 bits è specificata mediante i 3 bits più a sinistra. Il quarto bit specifica se l'istruzione coinvolgerà il registro A (valore 0) o B (valore 1) della ALU. I 4 bits più a destra specificano l'indirizzo nella RAM che serve all'istruzione. Abbiamo un numero molto limitato di istruzioni ma sono quelle che ci bastano per fare un esempio.

 

Istruzione macchina Istruzione assembler Descrizione operazione
Codice istruzione A/B Indirizzo operando    
0 0 0           JUMP Vai ad eseguire l'istruzione all'indirizzo ...
0 0 1           LOAD Carica in A o B il contenuto all'indirizzo ...
0 1 0           STOR Scrivi il contenuto di A o B nell'indirizzo ...
0 1 1           ADD Somma il contenuto di A e B (il risultato va in A)
1 0 0           HALT Ferma il flusso delle istruzioni

Proviamo ora ad utilizzare queste istruzioni per scrivere un programma assembler che esegue una somma ed immaginiamoci come questo programma potrebbe essere allocato nella memoria RAM. La tabella seguente riporta la lista delle istruzioni e, nella colonna all'estrema sinistra, gli indirizzi, delle parole della RAM nelle quali si trovano le istruzioni.

 

I Istruzione macchina Istruzione assembler Descrizione operazione
  Codice istruzione A/B Indirizzo operando    
0 0 0 1 0 0 1 0 1 LOAD,A,5 Carica in A il contenuto all'indirizzo 5 (c'è il numero 3)
1 0 0 1 1 0 1 1 0 LOAD,B,6 Carica in B il contenuto all'indirizzo 6 (c'è il numero 5)
2 0 1 1 0 0 0 0 0 ADD Somma il contenuto di A con quello di B (il risultato finisce in A)
3 0 1 0 0 0 1 1 1 STOR,A,7 Memorizza il contenuto di A all'indirizzo 7
4 0 0 0 0 1 0 0 0 JUMP,8 Vai ad eseguire l'istruzione all'indirizzo 8
5 0 0 0 0 0 0 1 1 3 Qui c'è il numero binario (11) che corrisponde a 3
6 0 0 0 0 0 1 0 1 5 Qui c'è il numero binario (101) che corrisponde a 5
7                   Qui finirà il risultato 8=3+5
8                   Qui c'è la successiva istruzione da eseguire

Si vede da questo esempio come sia importante che l'istruzione JUMP in posizione 4 vada a puntare ad una posizione di memoria dove vi sia effettivamente un'istruzione da eseguire. Se l'indirizzo specificato accanto all'istruzione JUMP fosse stato per sbaglio 7 anziché 8, l'unità di controllo avrebbe tentato di eseguire un codice probabilmente privo di significato causando molto probabilmente l'arresto del programma.

 

Importante: In altre parole, in una macchina costruita secondo il principio di Von Neumann, non vi è alcuna possibilità che l'unità di controllo possa riconoscere il tipo di informazione codificata nelle parole della RAM solo in base al loro contenuto; è il programma che deve essere scritto in maniera da accedere in modo corretto alle varie aree di memoria sapendo a priori qual'è il tipo di informazioni che vi è stato scritto. Errori di questo tipo, cosiddetti di indirizzamento, non sono affatto rari e la loro probabilità aumenta con la complessità del software. Questo spiega come mai programmi di uso comune anche molto diffusi possano improvvisamente cessare di funzionare correttamente o addirittura bloccare l'intero sistema operativo.