Sei sulla pagina 1di 11

ARCHITETTURA DI ELABORATORE

Dispensa Universitaria
Quest'opera è stata rilasciata sotto la licenza Creative Commons Attribuzione - Non
commerciale - Non opere derivate. Per leggere una copia della licenza visita il sito web
http://creativecommons.org/licenses/publicdomain/ o spedisci una lettera a Creative
Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
CAPITOLO 1
Dietro un programma #1
Comunicare con un sistema elettronico significa inviare segnali elettrici. I segnali che le
macchine comprendono sono quelli che identificano lo stato di ON e di OFF, ossia VERO e
FALSO. Di conseguenza l'alfabeto elettronico essendo formato da due "stati" distinti è definito
binario e viene numericamente rappresentato rispettivamente da 1 e 0. Queste due "lettere"
primitive sono chiamate cifre binarie o in inglese bit (binary digit). A livello più elettronico,
questi due momenti vengono implementati con l'assenza o la presenza di tensione elettrica. In
particolare lo stato ON è una tensione compresa tra 3v e 5v, mentre quella OFF da 0v a 0,4v.
Non a caso il "salto" che si deve fare per passare da OFF a ON è notevole. E’ chiamato in inglese
gap e serve per annullare gli effetti del rumore, in altre parole gli effetti di disturbo esterni.

I calcolatori eseguono senza controlli le istruzioni impartite loro, ossia stringhe di bit
comprensibili, effettivamente implementabili dall'hardware specifico. All'inizio le istruzioni
erano impartite direttamente in linguaggio macchina, ma il procedimento risultava essere
veramente lungo e noioso. Per questo motivo furono inventati i primi programmi che
traducessero in linguaggio macchina codici più vicini al linguaggio umano. Il primo fu
l'assemblatore (assembler) che associava un codice mnemonico basilare a stringhe di bit.
Questo linguaggio (chiamato assembly) richiede al programmatore di scrivere riga per riga le
istruzioni e lo costringe a pensare in relazione alla macchina specifica e alla sua struttura
fisica. Con l'andare del tempo si è risolto questo grosso problema progettando linguaggi ancora
più vicini al linguaggio umano (oggi chiamati linguaggi ad alto livello) che sono prima tradotti
nell’assemly relativo alla macchina e poi in codice macchina. Questi linguaggi risolvono molti
problemi come la facilità e l'indipendenza dell'algoritmo rispetto alla macchina usata. Il
programmatore può finalmente risolvere un problema concentrandosi solamente sull'algoritmo
ad altro livello e non più sull'implementazione hardware. Inoltre il semplice ragionare in
linguaggio naturale è indubbiamente più facile e intuitivo. Il linguaggio ad alto livello inoltre
incrementa la produttività, la velocità e la portabilità. Un programma in C può essere
compilato su sistemi diversi, ma risulta funzionare lo stesso. Un programma in assembly
funziona solamente sulla macchina a cui il programmatore si è riferito. Il traduttore di questi
linguaggi ad alto livello è chiamato compilatore se traduce completamente l'algoritmo in una
volta sola, oppure interprete se l'algoritmo viene di volta in volta, ad ogni utilizzo, ritradotto
riga per riga.

Alto livello Compilato Assemblato


C = A + B add $t0, $s1, $s2 00000010001100100100000000100000

Una volta che la programmazione diventò matura, molti professionisti si accorsero che
riutilizzare programmi già fatti, facilitava non poco il loro lavoro. In questa logica furono create
librerie contenenti routine di largo utilizzo. Quelle iniziali permettevano il controllo di ingresso
o uscita di dati, come ad esempio verso la stampante. Una procedura insita di controllo poteva
ad esempio gestire errori come la mancanza di carta e via dicendo. Divenne evidente
l'importanza di programmi ad-hoc per la gestione delle risorse e per la supervisione e il
controllo. Questi programmi sono alla base del concetto di Sistema Operativo ossia di
procedure e programmi che gestiscono le risorse del sistema a vantaggio dei programmi che
devono essere eseguiti. Man mano che il software si specializzava, sono nate le categorie come
software di sistema per le utility oppure software applicativo per programmi orientati
all'utente come editor testuali o fogli elettronici.
Dietro un programma #2
Abbiamo visto il compilatore, poi l'assemblatore ed anche un esempio di come un'istruzione
assembly è tradotta in linguaggio macchina. Approfondiamo questo tema senza addentrarci
troppo nello specifico. Per semplicità ci riferiamo alle istruzioni di un processore particolare
che si chiama MIPS! Ovviamente di MIPS ci sono varie versioni ed implementazioni, ma questo a
noi non interessa. Quello che c’interessa sapere è come sono rappresentate le istruzioni in
linguaggio macchina! Prendiamo l'esempio di sopra. Se noi contiamo tutti i bit della parola, ci
accorgiamo che sono esattamente 32! Ovviamente questo numero non è a caso. Ci stiamo,
infatti, riferendo ad una parola di 32bit... il nostro processore quindi può gestire un’istruzione
di 32bit! A questo punto la domanda successiva è: ma come si costruisce una parola che data al
processore prenda il significato di un comando? Ovviamente per com’è costruito il processore, il
suo lavoro "meccanico" è regolato da codici operativi, che dati in ingresso ad un circuito logico
producono un effetto conseguente in uscita! I codici operativi non sono altro che sotto-stringhe
di bit appartenenti alla parola di 32bit originaria. Prendiamo sempre l'esempio precedente:

00000010001100100100000000100000

In verità questa stringa è divisibile in ben 6 parti che identificano sei sotto-stringhe differenti.
Eccole:

000000 - 10001 - 10010 - 01000 - 00000 - 100000

Queste sotto-stringhe rappresentano l'istruzione assembly add $t0, $s1, $s2:

0 17 18 8 0 32
Op rs rt rd Shamt Funct
000000 10001 10010 01000 00000 100000

La prima riga è la traduzione dell'ultima in decimale, la seconda è le funzioni delle sotto-


stringhe, che adesso analizziamo! Rs non è altro che il registro sorgente #1, rt il #2, rd quello di
destinazione. Prendendo il comando assembly, ci accorgiamo che rs = $s1, rt = $s2 e rd = $t0!
Ma perchè rs nel linguaggio macchina equivale ad un 17, rt a un 18 e rd ad un 8? Molto
semplicemente perchè i registri del processore sono elencati e $s1 è il 17, s2 è il 18 e $t0 è 8
nella lista! Ecco la lista completa per il MIPS:

Registro Numero
$zero 0
$at 1
$v0-1 2-3
$a0-3 4-7
$t0-7 8-15
$s0-7 16-23
$t8-9 24-25
$k0-1 26-27
$gp 28
$sp 29
$s8 30
$ra 31
Continuiamo la nostra analisi. Il codice Op è 0(dieci), shamt 0(dieci) e funct 32(dieci). Anche
questi codici seguono ovviamente un concetto ben preciso che per il momento è impossibile
spiegare in quanto sarebbe necessaria la conoscenza approfondita dell'hardware del MIPS (che
vedremo nei prossimo capitoli). Quello che adesso c’interessa è che questo formato d’istruzione
composta da “6bit+5bit+5bit+5bit+5bit+6bit” prende il nome di formato-R a cui appartengono
le istruzioni logico-aritmetiche!

Ma ci sono altri tipi d’istruzioni! Quanto formati ci sono? In ogni modo tutte le istruzioni MIPS,
sono racchiuse in un insieme ristretto di formati. In totale i formati sono 3! Format-R, Format-I
e Format-J! Il primo lo abbiamo già analizzato ed è sempre composto nel seguente modo:

op rs rt rd shamt funct

Il secondo rappresenta le istruzioni cosi dette immediate (immediate).

op rs rd address/immediate

Per esempio l'istruzione addi $t0, $s1, 3, somma il contenuto del registro $s1 immediatamente
ad una costante 3 (da qui immediato)! Ecco perché all'istruzione serve un solo registro
sorgente! I restanti 16 della sotto-stringa address/immediate rappresenteranno il numero in
complemento a due (che vedremo nei prossimi capitoli) della costante! Per precisione ecco la
stringa di bit reale del comando addi sopra scritto!

001000 10001 01000 0000000000000011

Potete notare come il codice Op ora sia 8 e non più 0 come nel caso dell'istruzione add!

Il terzo formato, Format-J, rappresenta quello per i salti incondizionati. Le istruzioni di salto
incondizionato rappresentano solamente un codice Op e un indirizzo di memoria, che contiene
le istruzioni del programma che vogliamo eseguire! In poche parole noi ordiniamo il salto in un
indirizzo di memoria che contiene l'istruzione da eseguire... anche in questo caso la struttura
hardware del processore aiuterebbe a capire, ma si deve aspettare il capito dedicato a questa
spiegazione! Ecco lo schema del Format-J:

op target address

Notiamo immediatamente l'enorme disponibilità di rappresentazione per l'address. Esattamente


26bit di spazio, quindi 2^26 possibili indirizzi di memoria! Questo perchè il programma può
avere una lunghezza notevole, e l'istruzione deve poter indicizzare il processore su indirizzi di
memoria effettivamente rappresentabili all'interno della parola!

Dopo quest’excursus veramente veloce sulle istruzioni del MIPS, terminiamo questo paragrafo
con un esempio di programma ad alto livello tradotto in assembly e poi in linguaggio macchina!
Prima la tabella delle istruzioni con i relativi codici!

Formati 6bit 5bit 5bit 5bit 5bit 6bit


Format-R Op Rs Rt Rd Shamt Funct
Format-I Op Rs Rd address/immediate
Format-J Op target address
Esempio:

Alto livello Assembly (senza controllo overflow, per


MIPS):
a = 2; addi $s0, Szero, 2
for (i = 0, i<100, i++) FOR: mult $s0, $t0
a = a*i; mflo $s0
addi $t0, $t0, 1
slti $t1, $t0, 100
bne $t1, $zero, FOR

Esadecimale
0x08 0x00 0x10 0x0002
0x00 0x10 0x08 0x00 0x00 0x18
0x00 0x00 0x00 0x10 0x00 0x12
0x08 0x08 0x08 0x0001
0x0A 0x08 0x09 0x00C4
0x05 0x09 0x00 0xFFFB

Binario
00100000000100000000000000000010
00000010000010000000000000011000
00000000000000001000000000010010
00100001000010000000000000000001
00101001000010010000000011000100
00010101001000001111111111111011
Dentro la scatola
Già osservando un calcolatore dall'esterno possiamo facilmente notare dispositivi d’ingresso e
d’uscita. La tastiera e il mouse sono ad esempio dispositivi d’ingresso dati, mentre il monitor e
la stampante di uscita. All'interno noi abbiamo invece dispositivi più complessi e che eseguono,
come l'hard disk ad esempio, compiti sia d’ingresso che d’uscita. All'interno del case un
componente fondamentale è la scheda madre (motherboard) che è praticamente la rete di
interconnessioni che collega i componenti e le periferiche tra loro. In questa maglia
d’informazioni possiamo notare blocchi rettangolari scuri che sono componenti
tecnologicamente avanzati denominati circuiti integrati o chip. Oltre ai circuiti
d’interconnessione, la scheda madre è composta dalla memoria e dal processore. La memoria è
dove i programmi e i dati dei programmi in esecuzione sono allocati per essere usati dal
processore che è invece la parte attiva della scheda, quella che effettivamente esegue i
comandi impartiti! Il processore è abbreviato in CPU ossia Central Processing Unit. Volendo
addentrarci ancora più in profondità, all'interno del processore troviamo l'unità d’elaborazione
dati e l'unità di controllo. La prima esegue le operazioni logico-aritmetiche, la seconda
impartisce gli ordini coordinando gli ingressi e le uscite e gestendo la memoria e i dispositivi
connessi. Per quanto riguarda la memoria abbiamo la RAM e la cache. La Random Access
Memory contiene il programma e i dati del programma. Questa memoria essendo RAM richiede
tempo sempre uguale per leggere o scrivere in qualunque cella di memoria, contrariamente ai
nastri o ad un hard disk. La memoria cache senza entrare nel dettaglio è una memoria molto
veloce che funziona da buffer per la RAM. Ovviamente più si va in profondità nei dettagli, più si
scoprono cose nuove e complicate. Tuttavia un certo livello d’astrazione è d'obbligo anche nella
progettazione di sistemi complessi. Un livello d’astrazione è ad esempio l'architettura
dell'insieme d’istruzioni oppure architettura del set d'istruzioni o ancora più semplicemente
architettura. In inglese Instruction Set Architecture oppure ISA. L'architettura di un elaboratore
identifica tutto ciò che quell'elaboratore può fare o non può fare, indicando ai programmatori
tutte le informazioni necessarie per la codifica di un algoritmo. L'architettura non è
l'implementazione di se stessa. L'implementazione di un’architettura è, infatti, la struttura
fisica, l'hardware vero e proprio! L'architettura ricopre un ruolo chiave. Per fare un esempio da
parte Macintosh, programmi per PowerPC non sono eseguibili su 68000 e programmi in 68000
non sono completamente eseguibili in PowerPC. Invece da parte l'Intel all'interno della famiglia
80x86, programmi per l'8086 del 1978 sono ancora eseguibili nel Pentium Pro.
I circuiti integrati: alimento per l'innovazione
Un transistor si comporta come un interruttore controllato dall'elettricità. Un circuito
integrato è composto di decine di migliaia di transistor in un singolo frammento di silicio (il
chip). Tra i primi chip e quelli moderni c'è molta differenza. La prima più evidente è la
quantità di transistor presenti nel frammento di silicio. Oggi i circuiti integrati hanno milioni di
transistor e sono definiti VLSI ossia Very Large-Scale Integrated Circuit (circuito integrato a
larghissima scala d’integrazione). Questo paragrafo renderà chiaro il processo industriale che
vede protagonista un qualunque tipo di circuito integrato!

Inizialmente la produzione del processore incomincia da un blocco di silicio. Il silicio è un


componente molto importante in questo campo poichè è un semiconduttore e con un processo
chimico particolare è possibile "arricchirlo" in modo da permettetegli di comportarsi in uno dei
tre modi seguenti:

• Eccellente conduttore (come il rame e l'alluminio)

• Eccellente isolante (come la plastica e il vetro)

• Eccellente "interruttore" (ossia può avere la capacità di condurre o no a seconda di


particolari condizioni)

Un transistor ovviamente rientra nell'ultima categoria! All'inizio del processo industriale, si


hanno blocchi di silicio simili a grosse salsicce chiamati lingotti. I lingotti sono poi "affettati" in
sottili dischi, i wafer, che non sono spessi più di 2mm e posso essere larghi dai 15-30cm ai 30-
60cm. Seguendo un processo chimico delicato chiamato pattern il wafer è reso, nelle varie
aree, conduttore, isolante e transistor. Ovviamente ogni minima sbavatura nel deposito delle
sostanze atte alla reazione chimica produce la perdita del chip nell'area in cui l'errore è
avvenuto. Non esiste un wafer perfetto! I difetti avvengono sempre ed è un fatto molto
importante da tenere in conto. Più il processore è piccolo e più l'errore causa meno perdite. Per
questo motivo il Pentium Pro, che richiederebbe un'area maggiore rispetto al Pentium, è
composto di due elementi distinti, uniti poi tra loro. In questo modo i progettisti hanno evitato
che la solita quantità d’errori presenti nella realizzazione del wafer rendesse inutilizzabile
maggiori quantità di prodotti finiti! Il lavoro seguente alla creazione del wafer è il taglio dei
componenti chiamati die (schegge) che sono i veri e propri chip. Avviene adesso il primo
processo di collaudo che vede essere scartati una buona quantità di die. Quelli risultati sani
sono infine incastrati nel package, che è il contenitore nero descritto nel paragrafo
precedente, e ritestati. Questa volta i chip con errore sono nettamente inferiori. Finito il
processo, il circuito integrato è pronto per essere venduto!
Inquadramento storico
Forse il primo vero e proprio calcolatore elettronico per uso generale è stato l'ENIAC
(Electronic Numerical Integrator and Calculator) progettato da J. Presper Eckert e John
Mauchly alla Moore School della Pennsylvania University. Fu finanziato dall'US Army e usato
durante la Seconda Guerra Mondiale. La sua esistenza fu resa pubblica solo nel 1946! L'ENIAC
era un enorme elaboratore da 24m di lunghezza, 3m d’altezza e 2m di larghezza con 20 registri
da 10 cifre lunghi 60cm. Possedeva 18.000 valvole, 70.000 resistenze, 10.000 condensatori,
6.000 interruttori in un totale di 30 tonnellate! Ovviamente la programmazione poteva
richiedere un'intera giornata. Tuttavia l'ENIAC poteva eseguire salti condizionati ed era, come
già detto, programmabile. Caratteristica importante ed innovativa per l'epoca. Nel 1944 John
von Neumann entrò nel progetto ENIAC con lo scopo o meglio l'dea di progettare un calcolatore
con memoria che potesse immagazzinare le istruzioni e i dati del programma, tutto a vantaggio
ovviamente della programmabilità! Fu creato così l'EDVAC (Electronic Discrete Variable
Automatic Computer), ma cosa più importante lo standard d’architettura principale ancora
adesso in uso sotto il nome di macchina di von Neumann!

Il primo computer funzionante e completo di memoria per istruzioni e dati fu però l'EDSAC
(Electronic Delay Storage Automatic Calculator) progettato e completato nel 1949 da Maurice
Wilkes della Cambridge University. Una sua versione più piccola e il primo prototipo di questo
tipo di elaboratore fu un anno prima il Mark-1 costruito nella Manchester University! Per amor
di precisione il Mark-1 e la serie Mark-2/3/4 fu creata a Harvard (poi la Manchester University si
appropriò del nome) all'epoca dell'ENIAC ed erano elaboratori con una architettura a memoria
particolare. Possedevano una memoria per le istruzioni ed una seconda per i dati! Oggigiorno
l'architettura Harvard identifica una macchina a singola memoria per le istruzioni più una
cache per i dati.

Eckert e Mauchly fondarono nel 1947 l’Eckert-Mauchly Computer Corporation e il loro primo
prodotto fu il BINAC costruito per la Northrop nel 1949. L'azienda fu, per problemi economici,
acquistata dalla Remington-Rand che costruì l'UNIVAC (Universal Automatic Computer). Quando
fu messo in commercio nel 1951 per 1 milione di dollari, ne furono costruiti ben 48 e per questo
fu il primo calcolatore commerciale di successo! Nel 1950 l'IBM, che si occupava di schede
perforate e automazione d'ufficio, cominciò ad entrare "nel giro" degli elaboratori. Il suo primo
risultato fu l'IBM-701 e 2 per calcoli e gestione di grandi quantità di dati. Vennero l'IBM-704 con
memoria a nuclei di ferrite e una velocità di qualche kHz, e l'IBM-709 con l'introduzione del
canale I/O! Da questo momento si conclude la prima generazione di computer (1946-1955) .
La seconda generazione (1952-1963) vede la nascita dell'IBM-7000 non più a valvole ma a
transistor e del FORTRAN (Formula Transistor) che è stato il primo linguaggio ad alto livello.

La terza generazione (1964-1971) nasce con l'avvento dei circuiti integrati (LSI) e della prima
famiglia di calcolatori IBM System/360. Un anno più tardi nacque il PDP-8 della Digital
Equipment Corporation che fu il primo minicomputer commerciale dell'epoca. Questo computer
diede inizio alla progettazione di sistemi miniaturizzati fino al 1971, anno nel quale l'Intel
produsse il primo microprocessore 4004.

La quarta generazione (1971-1977) ha come protagonista il Cray-1, il primo supercomputer


della storia di Seymour Cray e l'introduzione del microprocessore (VLSI) Intel 4004. Di pari passo
alla progettazione di sistemi sempre più potenti e di conseguenza costosi, personaggi all'epoca
sconosciuti cominciarono a creare elaboratori sempre più economici e piccoli con l'intento di
rendere possibile l'acquisto si elaboratori anche ai singoli cittadini che potevano in questo modo
usarlo a casa loro. Si sta parlando dell'avvento del primo Personal Computer; l'Apple 2 di Steve
Jobs e Steve Wozniak! Ma la storia ha destinato un'altra fine a questo PC con ben quattro anni
d’anticipo rispetto a quello che è divenuto lo standard tutt'ora imbattuto. Infatti, fu proprio
l'IBM col processore Intel e software Microsoft ad ottenere la fetta di mercato più consistente!
Ancora oggi questa combinazione risulta essere come detto quella più diffusa.

La quinta generazione (dal 1977 in poi) rappresenta tutto ciò che riguarda lo sviluppo di
processori e tecnologie ad-hoc come i sistemi grafici e quelli multiprocessori e l'ottimizzazione
e la differenziazione di tecnologie già presenti come i processori RISC (Reduced Instruction Set
Code)! Infine la sesta generazione è quella che sta prendendo piede in questo momento e sarà
il nostro futuro: sistemi intelligenti, multimedialità, macchine parallele, elaboratori ottici e
quantici...

Esiste poi una grandissima quantità di processori che non possono essere trattati ma sono
fondamentali per il corretto funzionamento di quasi ogni device e non solo. Per fare un
esempio, oggi, le stampanti e le macchine digitali per fotografie e video usano processori
sviluppati appositamente! Sebbene spesso questi sistemi non siano visti con gli occhi giusti o a
volte proprio non visti, questi processori sono importantissimi!

Qui di seguito è presente una classifica degli elaboratori per genere:

• Mainframe (multiutente, di grosse dimensioni e di grande potenza, server di grosse


dimensioni)

• Supercomputer (calcolo vettoriale e parallelo)

• Minicomputer (piccoli mainframe, server)

• Microcomputer (PC)