MACCHINE DI VON NEUMANN

1. INTRODUZIONE

La maggior parte dei calcolatori attualmente in uso sono macchine di Von Neumann, dal nome dell'ideatore dell'architettura (struttura logica) con cui sono costruiti.

Una macchina di Von Neumann è costituita da un sistema di interconnessione (bus e/o multiplexer) tramite cui sono collegati 4 tipi di unità logiche (cioè ogniuna che esegue un certo compito logico): Queste unità logiche sono ottenute combinando i blocchi di cui si è parlato nel capitolo precedente, a creare circuiti più complessi.

CU e ALU sono quasi sempre integrate su un unico chip che prende il nome di CPU (Central Processing Unit).
Per questo, CU e ALU sono in genere connessi tramite multiplexer. CPU, memoria centrale, I/O, invece, sono in genere connessi tramite bus.
Architettura

2. SISTEMI DI INTERCONNESSIONE

Per connettere le unità logiche di un calcolatore, ci sono tre metodi. (seriale-parallelo e multiplexer-bus: che relazione c'è?)

3. ALU (Unità Aritmetica e Logica)

3.1 Introduzione

Schema a blocchi:
ALU
Funzione logica: operazioni logiche (not, and, or, ..., comparazione logica, ...) e operazioni aritmetiche (somma, differenza, shift, complementazione, opposto, comparazione aritmetica,...).

Dunque la ALU non è in grado di eseguire nè moltiplicazioni, nè divisioni direttamente. Inoltre può lavorare direttamente solo su numeri naturali o interi e su stringhe con significato logico.

3.2 Funzionamento

Operandi: ingressi ai quali bisogna mandare le stringhe binarie su cui compiere l'operazione scelta.
Funzione: ingressi su cui mandare il codice che identifica l'operazione da compiere. Noi useremo il seguente codice:
Codice Operazione
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
AND
OR
NOT
COMPARAZIONE logica e aritmetica
TEST B
ADD
SHIFT LEFT
SHIFT RIGHT
Risultato: uscite su cui si ottiene la stringa risultante.
Flag: uscite che segnalano determinati eventi logici:
Flag Evento
Z
segnala se il risultato dell'operazione logica o aritmetica compiuta ha come risultato la stringa nulla
N
segnala se il risultato dell'operazione compiuta è un numero negativo;
questa segnalazione ha senso solo per operazioni aritmetiche,
cioè quando le stringhe operando hanno significato numerico;
tuttavia la ALU segnala comunque come negative anche le stringhe con significato logico,
perchè si preoccupa soltanto di rilevare se il MSB è 1
(vedere "Rappresentazione in Complemento a Due"), quasiasi sia la natura della stringa.
C
segnala il trabocco di un uno sul MSB o LSB
(trabocchi di zero non contano visto che il numero non cambia: 00214 è uguale a 214).
V
segnala un overflow o underflow.
Il trabocco segnala che una stringa rappresentante un numero naturale o un valore logico (cioè in base due "standard" -senza bit segno e NON in complemento a due) ha altrepassato le dimensioni della word e quindi non rappresenta più il valore voluto. Per fare ciò la ALU controlla che l'uscita di trabocco dei vari circuiti da cui proviene la stringa non sia attiva.
L'overflow segnala invece che una stringa rappresentante un numero intero (cioè in complemento a due) ha oltrepassato la dimensione della word e quindi non rappresenta più il valore voluto. Per fare ciò la ALU controlla il MSB degli operandi: se entrambe gli operandi hanno MSB pari ad uno, c'è stato overflow e il flag V viene attivato.
Il trabocco non ha senso per numeri rappresentati con stringhe in complemento a due
(ad es. 1100Ca2+1010Ca2 da un risultato errato 0110Ca2, mentre 1100Ca2+1100Ca2 da un risultato giusto 1000Ca2, dunque il trabocco non dà alcuna indicazione sulla correttezza del risultato),
così come l'overflow non ha senso per numeri naturali e valori logici rappresentati in base due con metodo "standard".
La ALU, tuttavia, segnala entrambe le condizioni senza occuparsi del significato delle stringhe che elabora.

4. MEMORIA CENTRALE

4.1 Introduzione

Schema a blocchi:
MemoriaCentrale
insieme di registri di memoria di capienza pari alla lunghezza della word; ogni registro prende nome di CELLA di memoria.
Funzione logica: scrittura di stringhe in memoria e lettura di stringhe precedentemente memorizzate.

4.2 Funzionamento

A: ingressi a cui va mandata la stringa da memorizzare
B: ingressi a cui va mandato l'indirizzo del registro su cui si vuole memorizzare A / da cui si vuole leggere C.
    Per semplicità progettuale, anche questo ingresso accetta solo stringhe lunghe una word
C: uscita su cui si può leggere la stringa in memoria
Funzione: specifica se si vuole leggere o scrivere sulla memoria

Chi programma vede la memoria centrale come vettore unidimensionale di celle il cui indice, detto indirizzo, identifica univocamente ogni registro e permette di accedervi sia in lettura che in scrittura.
L'entrata B dovrebbe essere gestita da un decodificatore con input l'indirizzo del registro e con tante uscite quante sono le celle di memoria, così da poter mandare ad ogniuna di esse gli opportuni segnali.

La memoria centrale è una memoria ad accesso casuale: per raggiungere un registro non è necessario scorrere tutte le celle precedenti, come succede invece per le memorie dette ad accesso sequenziale. Per questo la memoria centrale viene spesso chiamata RAM (random access memory).

Sebbene la memoria centrale sia un calderone in cui finiscono sia istruzioni che dati, questa viene spesso organizzata in compartimenti stagni proprio per proteggersi da possibili errori. In genere esiste una parte riservata al sistema operativo [ad es. per il vettore delle interruzioni e per tutto il codice del S.O.], una parte dedicata alle istruzuini del programma, un'altra porzione atta a contenere i dati ed una riservata allo stack. Questa divisione non è hardware ma logica.

È da notare, infine, che prima che una operazione di lettura o scrittura venga completata, trascorre un certo tempo detto tempo di accesso, dovuto alla lentezza delle porte che costituiscono registri e decodificatori.

4.3 Allineamento della memoria (trovare un posto migliore)

La memoria centrale è organizzata in word, però spesso è possibile indirizzare anche pezzi di word. Ad esempio, se la word è di 4 byte, spesso è possibile operare anche sul singolo byte. Il byte su cui si può operare è quello all'inizio o alla fine della word (a seconda della scelta progettuale) e deve sempre essere allineato all'inizio o alla fine della word; tutto il resto della parola può contenere nulla oppure l'estensione del segno se vi era memorizzato un numero in complemento a due.

4.4 Accorgimenti pratici

L'entrata B della memoria dovrebbe essere gestita da un decodificatore con input l'indirizzo del registro e con tante uscite quante sono le celle di memoria, così da poter mandare ad ogniuna di esse gli opportuni segnali. Se si considera che B, sugli attuali computer, è in genere di 32 bit, si capisce che il decoder dovrebbe avere 4 miliardi di piedini di uscita (232). Allo stato attuale, però, il massimo numero di piedini che si riesce ad inserire in un chip è dell'ordine di qualche centinaio.
Diventa necessario usare un "trucco" a livello hardware (invisibile a chi programma, che continua a vedere la memoria come un vettore unidimensionale) per poter indirizzare un tale quantitativo di celle.
Il trucco consiste nel frazionare l'indirizzo B: nel caso di 32 bit, si divide B in pezzi da 8 bit ciascuno. Ogni pezzo viene considerato come una coordinata: x, y, z, w.
Schema
Ogni pezzo da 8 bit viene gestito da un decodificatore con otto ingressi e quindi 256 uscite (che è un numero di piedini accettabile). Le uscite dei 4 decodificatori vengono poi messe in AND fra loro.

In commercio si trovano chip di memoria costruiti come visto (registri, input, input per indirizzo, uscite). Assemblando questi circuiti si ottengono i banchi di memoria veri e propri.
Si supponga di avere chip che possano contenere 4 parole da 4 bit (e quindi con due linee di indirizzamento):
Schema
Si supponga di voler costruire con essi una memoria con capacità identica a quella dei chip di cui sopra, ma che possa lavorare su parole lunghe il doppio. Ecco come fare:
Schema
Aggiungendo altri chip si possono gestire parole più lunghe.
Si supponga ora di voler costruire con essi una memoria che lavori con parole di lunghezza identica a quella dei chip di cui sopra, ma con capacità doppia (otto parole invece di quattro). Ecco come fare (servono tre linee di indirizzamento per gestire 8 parole):
Schema
Delle tre linee di indirizzamento, due le connetto a quelle dei chip, una la uso come segnale abilitatore degli innput dei chip.
Le uscite dei chip vengono gestite da porte OR (basta che da parte di un chip arrivi un uno ad una porta OR perchè l'output sia 1).

Si possono combinare i due precedenti metodi per ottenere banchi di memoria di capacità doppia ed in grado di gestire parole lunghe il doppio.

L'ingresso B è lungo una parola. Questa è una limitazione alla quantità di memoria indirizzabile dalla macchina. Se ad es. la parola è di 16 bit, si possono indirizzare al massimo 216 (circa 65 000) celle - come si suol dire, il campo di indirizzamento va da 0 a 216.
Può essere necessario disporre di più indirizzi, ovvero occorre una memoria centrale di dimensioni maggiori a questo limite superiore.
Pagine A tal proposito si usa un registro di memoria speciale detto registro di estensione, che si trova in una zona della RAM di nome MM (Memory Managment). Tale registro contiene i bit in più (rispetto alla lunghezza della parola) che si vogliono usare per indirizzare la memoria.
Si può pensare in questi termini: la memoria viene divisa in pagine e ogni pagina è direttamente indirizzabile tramite la word che arriva all'ingresso B. Nel registro, invece, viene memorizzato il numero di pagina che si stà considerando.
Per quanto illustrato, la memoria centrale viene divisa in memoria fisica - quella realmente presente "on board" - e memoria indirizzabile - quella parte di memoria fisica direttamente indirizzabile tramite una parola.
Introdurre una struttura a pagine della memoria ha i seguenti svantaggi: occorrono nuove istruzione per gestire il registro di estensione (ad es l'istruzione "salto di pagina"); si ha un aumento del tempo di accesso; un programma non può occupare più di una pagina e i salti fra moduli di programma in pagine diverse sono più complicati [le istruzioni di salto hanno uno spazio per l'offset o indirizzo che non può gestire il registro di estensione, dunque occorre usare anche istruzioni speciali].

5. CONTROL UNIT

È richiesto lo studio del file quattro in parallelo a questo capitolo.

5.1 Introduzione

La Control Unit è costituita dai seguenti elementi base: e dai seguenti elementi non di base: CU

5.2 Program Counter

Il PC è un contatore preselezionabile.
Il suo compito è di gestire la memoria centrale: le sue uscite sono collegati agli ingressi di indirizzamento della memoria centrale.
Essendo un contatore, scandisce la memoria in modo sequenziale. Se, però, è necessario interrompere la sequenzialità del conteggio per saltare ad un certo indirizzo, si può usare l'ingresso del contatore preselezionabile, collegato al codificatore di comandi.

Caratteristica delle macchine di Von Neumann è di avere un solo PC. Ciò è equivalente ad affermare che le macchine di Von Neumann sono sequenziali: esse possono eseguire una sola istruzione alla volta.
Dall'unicità del PC si deduce anche l'unicità della memoria centrale: solo il PC ha accesso alla memoria e se esso è unico, anche la memoria lo deve essere.

5.3 Decodificatore di Istruzioni

La stringa letta dalla memoria tramite il PC viene inviata al decodificatore di istruzioni.
Questo decodifica i vari campi dell'istruzione e li manda al codificatore di comandi.

5.4 Codificatore di Comandi

Questo circuito riceve le istruzioni decodificate e fa tutto il necessario per eseguirle.
Ad es. si connette all'ingresso "funzione" della ALU e le comunica che operazione fare; connette quindi la memoria centrale o i registri interni alle entrate della ALU; connette poi l'uscita della ALU con la memoria centrale o i registri interni per memorizzare il risultato.
Si ricorda ancora che non tutte le istruzioni richiedono l'uso della ALU.

Si noti la differenza fra istruzioni e comandi: le istruzioni sono comandi codificati, i comandi sono istruzioni decodificate.
A onor del vero si potrebbero costruire macchine che abbiano solo comandi e non istruzioni. Così facendo non sarebbero più necessarie le fasi di codifica e decodifica, aumentando velocità, economicità ed affidabilità dei calcolatori. Questo però non avviene perchè i comandi occuperebbero troppa memoria (esistono molti comandi, ogniuno può avere molti modi di indirizzamento degli operandi). La codifica è una sorta di compressione e per questo in memoria si trovano soltanto istruzioni e non comandi.

Visto il gran numero di istruzioni e indirizzamenti possibili, codificatore di comandi e decodificatore di istruzioni sono circuiti combinatori molto complessi e quindi costosi da progettare e costruire.
Talvolta, per risparmiare, essi vengono sostituiti da una micromacchina, ovvero una macchina di Von Neuman con micro-PC, micro-CPU e ROM al posto della RAM.
L'istruzione da decodificare arriva al micro-PC che controlla la ROM. Nella ROM, al contrario delle macchine di Von Neumann vere e proprie, ci sono sia istruzioni che comandi. Nel caso che il PC trovi direttamente il comando corrispondente all'istruzione ricevuta, il comando viene subito inviato in output. Se, invece, l'istruzione non ha un comando associato direttamente, le viene associato un micro-programma che,una volta eseguito, da in output il comando corrispondente all'istruzione. L'insieme dei microprogrammi viene detto firmware. Le microistrizoni con cui scrivere questi programmi sono molto poche.
Tutti questi passaggi sono trasparenti al programmatore assembly, tranne per il fatto che introducono un rallentamento nell'esecuzione dei programmi - a fronte, però, di una maggiore economicità.
Questo rallentamento può essere più o meno marcato a seconda del numero di istruzioni e del numero di comandi direttamente presenti nella ROM. È possibile espandere tali istruzioni o comandi semplicemente cambiando la ROM (o utilizzando una EPROM - tipo di memoria di cui non parleremo).

5.5 Generatore di Fase

Perchè un'istruzione sia eseguita da una macchina di Von Neumann sono necessarie le seguenti fasi: Il generatore di fase riconosce la fase nella quale ci si trova e la segnala al decodificatore di comandi.
Se ci si trova nella prima o nella seconda fase, infatti, il decodificatore deve fare le stesse operazioni qualsiasi sia l'istruzione.
Se, però, ci si trova nell'ultima fase, i compiti che il decodificatore deve svolgere variano da istruzione ad istruzione.
Appare evidente, quindi, che al decodificatore di comandi serve sapere in quale delle tre fasi il sistema si trova.

5.6 Registri di Memorizzazione Interni

Sono normali registri di memorizzazione lunghi una parola.

Il loro compito è identico a quello della memoria centrale: memorizzare dati su cui si sta operando.
Da un punto di vista logico, quindi, risultano superflui, ma la pratica mostra che è molto comodo averli.
Rispetto alla memoria centrale, infatti, essi sono più vicini e sono meno numerosi. Questo significa che sono più velocemente accedibili e più facilmente indirizzabili della memoria centrale.

Si usa dividere tali registri in due gruppi: Fra quelli ad uso speciali ci sono:

6. INPUT \ OUTPUT

È richiesto lo studio del file cinque in parallelo a questo capitolo.

6.1 Realizzazione

Ci sono due metodi per implementare l'unità di I\O.

6.2 Funzionamento

Il problema principale nel colloquio fra periferiche e CPU risiede nella differenza di velocità fra questi componenti.
Per riuscire a farle comunicare, quindi, bisogna usare vari accorgimenti.
Innanzitutto è necessario che le periferiche bidirezionali (periferiche su cui si può leggere e scrivere) abbiano almeno i seguenti tre registri: La comunicazione consiste nel trasferimento di dati fra memoria centrale o registri interni e registri di dato in ingresso o di dato in uscita della periferica.
Esistono poi i seguenti tre metodi per realizzare lo scambio di dati:

7. ALTRO

7.1 Introduzione

ALU, CU, memoria centrale e I\O sono le unità logicamente essenziali per le macchine di Von Neumann.
Tramite queste si possono fare tutte le operazioni che un computer sa fare.

Spesso, però, a queste unità logiche essenziali, vengono affiancate altre unità, specializzate in vari compiti.
Tali unità non sono più logicamente essenziali, visto che i compiti che esse svolgono potrebbero essere svolti anche soltanto da ALU, CU, memoria centrale e I\O via software (ovvero combinando varie istruzioni per eseguirli).
Ad es.: la ALU non sa calcolare direttamente il prodotto di due numeri, ma per fare un prodotto basta fare una serie di somme, cosa che la ALU sa fare. Basta quindi scrivere un programma che faccia ciò. Ad es.: per operare con numeri di lunghezza doppia al normale basta spezzare manualmente questi numeri su due word.
Vengono tuttavia aggiunte perchè velocizzano queste operazioni, dato che sanno eseguirle direttamente, con una sola istruzione - via hardware, come si dice - perchè hanno circuiti in grado di farlo.

Di queste unità aggiuntive vedremo soltanto l'unità aritmetica.

7.2 AU (Unità Aritmetica)

L'unità aritmetica (altrimenti detta coprocessore aritmetico o unità a virgola mobile) si occupa di moltiplicare e dividere numeri interi, nonchè di operare sui numeri reali rappresentati in virgola mobile e sui numeri in lunghezza doppia (lunghi due word anzichè una).