minilogo.gif (2094 bytes)

Introduzione all'architettura dei calcolatori

left.gif (1019 bytes) up.gif (1014 bytes) right.gif (1020 bytes)

La macchina di von Neumann

Come abbiamo accennato in precedenza, l'impiego di componenti più veloci non è il solo metodo per incrementare le prestazioni di un calcolatore; risultati analoghi, se non superiori -- e certamente più interessanti e significativi -- possono essere conseguiti con una opportuna organizzazione delle varie componenti hardware e un'adeguata sincronizzazione delle loro funzioni. Vedremo perciò nel seguito come la configurazione base di un sistema di elaborazione possa essere sottoposta a una serie di trasformazioni che la porteranno ad adattarsi con naturalezza ed efficienza alla struttura intrinseca di molti problemi computazionali.

Seguendo l'impostazione proposta in [16], possiamo descrivere l'architettura di quasi tutti i calcolatori oggi esistenti facendo ricorso soltanto a quattro tipi generali di unità funzionali astratte (Fig. 2):

 

Fig. 2 I quattro elementi fondamentali di una macchina astratta:
(a) processore di istruzioni, (b) processore di dati, (c) memoria,
(d) commutatore.

La struttura di tutti i moderni calcolatori discende da uno schema fondamentale comune, chiamato macchina di von Neumann, costituito da un processore di istruzioni, da un processore di dati e da due memorie; queste unità funzionali, interconnesse direttamente tra loro senza il tramite di alcun commutatore, formano la configurazione che appare in Fig. 3.

Fig. 3

Versione base della macchina di von Neumann.

Il processore di istruzioni, connesso alla prima memoria (memoria delle istruzioni), può estrarre da essa una singola istruzione, previa presentazione di un indirizzo che identifichi l'istruzione stessa. Il processore di istruzioni è inoltre connesso al processore di dati, a cui invia sia le richieste di esecuzione di determinate operazioni, sia gli indirizzi che serviranno a identificare gli operandi residenti nella seconda memoria (memoria dei dati); il processore di dati, a sua volta, esegue le operazioni richieste e restituisce al processore di istruzioni delle informazioni di stato (codici di condizione) relative all'esito di tali operazioni.

In maggior dettaglio, le funzioni che il processore di istruzioni è chiamato a svolgere sono le seguenti:

Le funzioni descritte hanno luogo all'interno di qualunque architettura che preveda la presenza di un processore di istruzioni; dobbiamo osservare tuttavia che esse non vanno necessariamente eseguite nell'ordine indicato, e che, sotto determinate condizioni, l'esecuzione di alcune di esse può anche essere evitata (ad esempio, quando le operazioni richieste al processore di dati riguardano informazioni già presenti entro di esso). L'ordinamento citato viene detto sequenza di esecuzione delle istruzioni in una macchina di von Neumann, e può essere rappresentato con precisione mediante il diagramma di stato di Fig. 4, in cui gli ovali rappresentano stati, cioè operazioni eseguite in un dato istante, le frecce continue caratterizzano la dipendenza temporale tra stati, e le frecce in grigio rappresentano comunicazioni tra il processore di istruzioni e le altre unità funzionali presenti nel sistema. Se in un dato istante il processore sta eseguendo le operazioni relative a un dato stato, diremo che quello stato è attivo in quell'istante; è facile vedere che il diagramma di stato, unitamente all'identificazione dello stato attivo ad ogni istante, fornisce una descrizione completa del comportamento del processore di istruzioni.

Fig. 4

Diagramma di stato del processore di istruzioni

Gli stati diventano attivi l'uno dopo l'altro, seguendo le frecce di dipendenza temporale, in accordo con le funzioni svolte dal processore di istruzioni: l'esecuzione di ogni istruzione richiede pertanto il transito dell'attività attraverso l'intero ciclo del diagramma di Fig. 4.

Il processore di dati esegue le seguenti funzioni:

Anche questo processo può essere rappresentato mediante un diagramma di stato strutturato ad anello (Fig. 5); esso differisce tuttavia dal diagramma di stato del processore di istruzioni per il fatto che alcune fasi possono essere attivate in concomitanza con altre. Vedremo fra breve come sarà possibile sfruttare questa proprietà.

Fig. 5

Diagramma di stato del processore di dati.

Le frecce in grigio nei diagrammi di stato, che rappresentano trasferimenti di informazioni (comunicazioni) tra i processori, indicano che le azioni corrispondenti devono essere sincronizzate: in altri termini, affinché la comunicazione abbia luogo, è necessario che entrambi gli stati messi in comunicazione nei due diagrammi siano simultaneamente attivi; è facile convincersi, inoltre, che uno stato coinvolto in una comunicazione non può diventare inattivo fino a che la comunicazione non sia stata completata. Una forma di comunicazione si ha, ad esempio, quando il processore di istruzioni deve inviare un indirizzo al processore di dati: in tal caso, la trasmissione da parte del processore di istruzioni può cessare solo dopo che il processore di dati abbia correttamente ricevuto le informazioni relative.

C'è una ragione essenziale per cui nello schema di Fig. 3 appaiono due unità di memoria, e consiste nel fatto che, a rigore, i loro comportamenti sono differenti: mentre le informazioni contenute nella memoria delle istruzioni si muovono solo verso il processore di istruzioni, quelle contenute nella memoria dati transitano da e verso il processore di dati; tale differenza di comportamento può all'occorrenza riflettersi in implementazioni diverse per i due tipi di memoria. In linea di principio, l'architettura di von Neumann non fa alcuna discriminazione tra dati e istruzioni: nelle strutture che abbiamo appena esaminato è senz'altro possibile raggruppare la memoria delle istruzioni e la memoria dei dati in un'unica unità funzionale senza che il comportamento della struttura venga ad esserne alterato; nella pratica, tuttavia, quasi tutte le macchine reali rendono difficile al programmatore lo sfruttamento di una simile equivalenza, e gli ambienti di programmazione tendono a discriminare sempre più nettamente fra dati ed istruzioni.

La memoria viene solitamente implementata sotto forma di livelli gerarchici, che sono caratterizzati dalla capacità (la quantità di informazioni contenute) e dal tempo di accesso (il tempo necessario per individuare le informazioni memorizzate, una volta noto il loro indirizzo): la tipica gerarchia (Fig. 6) prevede al livello più basso una memoria di massa, tipicamente a dischi magnetici, di capacità estremamente elevata ma piuttosto lenta (tempi di accesso dell'ordine delle decine di millisecondi (1)); al livello intermedio, una memoria centrale, di capacità più ridotta ma con tempi di accesso molto minori; al livello superiore, una memoria cache, con capacità ancora più ridotta ma estremamente veloce (tempi di accesso dell'ordine delle decine di nanosecondi (2)). Possiamo osservare come in una simile impostazione anche l'input/output possa essere assimilato ad un meccanismo per l'accesso ad un ulteriore livello di memoria -- ancora più basso rispetto alla memoria di massa -- rappresentato dal mondo esterno, con capacità infinita e tempi di accesso estremamente variabili.

Fig. 6

Implementazione gerarchica della memoria: (a) i livelli della gerarchia,
(b) capacità e tempi di accesso.

Altre particolarità che spesso si incontrano nei calcolatori reali consentono di stabilire ulteriori differenziazioni. Ad esempio, nella maggior parte delle macchine di von Neumann la selezione dell'istruzione successiva viene implementata mediante un contatore di programma (program counter); in alcuni sistemi, tuttavia, l'indirizzo dell'istruzione successiva è parte integrante dell'istruzione stessa. E' chiaro però che queste varianti non modificano la natura dell'architettura, che rimane pur sempre di von Neumann, ma vanno piuttosto considerate come dettagli di implementazione, e devono pertanto restare indistinguibili a livello di macchina astratta.


Note

  1. 1 millisecondo = 1 msec = 10-3 secondi.
  2. 1 nanosecondo = 1 nsec = 10-9 secondi.
minilogo.gif (2094 bytes)

Introduzione all'architettura dei calcolatori

left.gif (1019 bytes) up.gif (1014 bytes) right.gif (1020 bytes)

© 1997-2003 Paolo Marincola (Rome, Italy)
e-mail:
pmaNOSPAM@acm.org (eliminare i caratteri "NOSPAM" per ottenere l'indirizzo esatto)
Commenti, osservazioni e suggerimenti sono estremamente graditi.

Last revised: 2003-12-06 19:42