Assembly Base con NASM
Capitolo 7: L'architettura generale del computer
Come è stato spiegato in un precedente capitolo, sin dall'antichità gli esseri umani hanno
cercato di realizzare macchine capaci di svolgere in modo automatico calcoli più o meno
complessi; un esempio famoso è rappresentato dalla calcolatrice meccanica di Pascal
(1642) che attraverso un sistema di ingranaggi era in grado di eseguire semplici
addizioni. Un altro esempio famoso è rappresentato dalle macchine calcolatrici realizzate
dal matematico Charles Babbage a partire dal 1822; queste macchine, formate
da ingranaggi, cinghie, pulegge, catene di trasmissione, etc, divennero via via sempre più
evolute sino a permettere il calcolo di equazioni differenziali. Il caso delle macchine
di Babbage assume una importanza enorme nella storia del computer in quanto questo
scienziato aveva capito che se una macchina è in grado di svolgere un determinato calcolo,
allora può essere progettata in modo da svolgere qualsiasi altro calcolo; il ragionamento
di Babbage venne dimostrato matematicamente parecchi anni dopo da Alan Turing.
Si può dire che Babbage aveva intuito con più di un secolo di anticipo l'idea
fondamentale su cui si basano gli odierni calcolatori elettronici; questo scienziato non
riuscì però a mettere in pratica le sue teorie in quanto la tecnologia disponibile nel
XVIII secolo per la realizzazione di queste macchine era esclusivamente di tipo
meccanico.
Le considerazioni appena esposte ci fanno capire che le prime macchine di calcolo
automatico presentavano una architettura piuttosto rigida che permetteva loro di eseguire un
numero limitato di operazioni; le istruzioni di elaborazione, infatti, venivano incorporate
(cablate) direttamente nei meccanismi della macchina stessa e ogni volta che si presentava la
necessità di eseguire un calcolo differente, bisognava progettare una nuova macchina o, nella
migliore delle ipotesi, bisognava modificarne la struttura interna.
Le macchine calcolatrici di questo tipo vengono definite a logica cablata e presentano
come principale difetto la scarsissima flessibilità; il pregio fondamentale di una macchina
a logica cablata è rappresentato, invece, dalla elevatissima velocità di calcolo.
7.1 La macchina di Von Neumann
All'inizio del XIX secolo, nel mondo delle macchine di calcolo automatico è
iniziata una autentica rivoluzione legata principalmente al nome dello scienziato John
Von Neumann; come è stato spiegato nel Capitolo 2, Von Neumann ha osservato che
nella risoluzione di un problema attraverso una macchina, si possono individuare tre fasi
principali:
- immissione dei dati in ingresso
- elaborazione dei dati appena immessi
- presentazione in uscita dei risultati
Queste considerazioni hanno portato Von Neumann alla conclusione che i calcolatori
dovessero avere una struttura come quella schematizzata in Figura 7.1.
In questa struttura, chiamata Macchina di Von Neumann, notiamo la presenza di un
dispositivo di Ingresso o Input attraverso il quale vengono inseriti i dati
da elaborare; il dispositivo chiamato Memoria può essere visto come una sorta di
"magazzino" all'interno del quale vengono sistemati temporaneamente i dati appena immessi.
L'Unità Centrale di Elaborazione o Central Processing Unit (CPU) è
il cuore di tutto il sistema ed ha il compito di elaborare i dati immagazzinati nella
memoria; infine, il dispositivo di Uscita o Output ha il compito di presentare
i risultati delle elaborazioni appena effettuate.
Gli studi di Von Neumann hanno permesso la realizzazione di macchine di calcolo
automatico caratterizzate da semplicità costruttiva, potenza e flessibilità al punto che
ancora oggi, moltissime famiglie di computer (piattaforme hardware) si ispirano proprio a
questo tipo di architettura; in particolare, possiamo citare i PC basati sulla famiglia
dei processori Intel 80x86 e compatibili.
7.2 Il programma
L'aspetto veramente rivoluzionario che caratterizza una macchina di Von Neumann è
dato dal fatto che la memoria è destinata a contenere non solo i dati da elaborare, ma
anche le relative istruzioni di elaborazione; nel loro insieme i dati da elaborare e le
istruzioni di elaborazione formano un cosiddetto programma.
Si può immaginare la memoria come un grande contenitore suddiviso in tanti scomparti
ciascuno dei quali rappresenta una cosiddetta cella di memoria; per individuare in
modo univoco le celle, assegnamo a ciascuna di esse un numero progressivo 0,
1, 2, 3, etc, chiamato indirizzo di memoria. Grazie agli
indirizzi di memoria, possiamo accedere ad ogni cella, sia per immagazzinare in essa un
dato (accesso in scrittura), sia per leggere il suo contenuto (accesso in
lettura).
Vediamo ora come avviene l'esecuzione di un programma in una macchina come quella di Figura
7.1.
Riserviamo un'area della memoria ai dati in ingresso e a quelli in uscita; quest'area
rappresenta il blocco dati del programma. Riserviamo un'altra area della memoria
alle istruzioni di elaborazione; quest'altra area rappresenta il blocco codice del
programma. Inizializziamo poi un apposito contatore caricando in esso l'indirizzo
di memoria dove si trova la prima istruzione da eseguire; a questo punto il controllo
passa alla CPU che può iniziare la fase di elaborazione del programma.
Supponiamo, ad esempio, di avere in memoria il programma mostrato in Figura 7.2, con il
contatore che inizialmente contiene l'indirizzo 0000.
La CPU va all'indirizzo 0000 dove trova una istruzione che consiste nella
lettura del dato (3500) che si trova in memoria all'indirizzo 0005; mentre
la CPU esegue questa istruzione, il contatore viene incrementato di 1 e il
suo contenuto diventa quindi 0001.
La CPU va all'indirizzo 0001 dove trova una istruzione che consiste nella
lettura del dato (2300) che si trova in memoria all'indirizzo 0006; mentre
la CPU esegue questa istruzione, il contatore viene incrementato di 1 e il
suo contenuto diventa quindi 0002.
La CPU va all'indirizzo 0002 dove trova una istruzione che consiste nel
calcolo della somma dei due dati appena letti dalla memoria; mentre la CPU esegue
questa istruzione, il contatore viene incrementato di 1 e il suo contenuto diventa
quindi 0003.
La CPU va all'indirizzo 0003 dove trova una istruzione che consiste nel
salvare il risultato della somma (5800) nella cella di memoria 0007; come
si può notare, la cella 0007 è inizialmente vuota ed è destinata a contenere
il risultato delle elaborazioni effettuate dalla CPU. Mentre la CPU esegue
questa istruzione, il contatore viene incrementato di 1 e il suo contenuto diventa
quindi 0004.
La CPU va all'indirizzo 0004 dove trova una istruzione che segnala la fine
delle elaborazioni; a questo punto la CPU entra in pausa in attesa di ulteriori
richieste di elaborazione.
Non ci vuole molto a capire che il sistema appena descritto presenta una elevatissima
flessibilità; se vogliamo sostituire, ad esempio, l'addizione con una sottrazione, ci
basta modificare le apposite istruzioni del programma appena illustrato. Naturalmente,
le varie istruzioni devono appartenere ad un insieme riconosciuto dalla CPU;
questo insieme viene definito set di istruzioni della CPU.
Una macchina di calcolo automatico come quella appena descritta viene definita a
logica programmabile e presenta l'eccezionale caratteristica di poter svolgere
praticamente un numero illimitato di compiti differenti; naturalmente, le macchine di
questo tipo sono enormemente più complesse e quindi più lente rispetto alle macchine
a logica cablata.
7.3 Il microprocessore
Un'altra rivoluzione che ha letteralmente sconvolto il mondo delle macchine di calcolo
automatico è stata provocata dall'invenzione del microprocessore, avvenuta nel
1970; questa invenzione è legata anche al nome dell'italiano Federico
Faggin che all'epoca lavorava come progettista in una piccola e giovane società
della Silicon Valley chiamata Intel. Insieme ai suoi colleghi,
Faggin si rese conto che l'evoluzione tecnologica aveva raggiunto ormai un
livello tale da permettere la possibilità di miniaturizzare le porte logiche e di
inserirle in grande quantità in uno spazio estremamente ristretto; in particolare, i
progettisti della Intel riuscirono a fabbricare interi circuiti logici
direttamente all'interno di un piccolo blocco di materiale semiconduttore chiamato
chip. In questo modo ottennero un microcircuito che integrava al suo interno
numerose R.C. come quelle presentate nel precedente capitolo; attraverso un
apposito sistema di controllo esterno, questo microcircuito, che venne chiamato appunto
microprocessore, poteva essere pilotato in modo da fargli svolgere una numerosa
serie di operazioni logico aritmetiche.
Il termine microprocessore è sinonimo quindi di micro CPU; nel caso
generale comunque il termine CPU indica una rete logica complessa capace di
eseguire una serie più o meno numerosa di operazioni logico aritmetiche.
La prima CPU realizzata dal gruppo di progettisti di cui faceva parte anche
Faggin è stata chiamata 4004 ed aveva una architettura a 4 bit;
nel 1972 è nata la CPU 8008 con architettura a 8 bit. Nel
1974 Faggin, prima di uscire dalla Intel, progettò la CPU
8080 che aveva sempre una architettura a 8 bit, ma garantiva prestazioni
notevolmente superiori rispetto alla 8008; successivamente Faggin nel
1975 fondò la società Zilog e progettò la fortunatissima CPU
Z80 a 8 bit che andò ad equipaggiare i famosissimi micro computer
Sinclair ZX Spectrum.
A partire dagli anni 80 sono comparse sul mercato CPU sempre più potenti
ed avanzate; in particolare, la famiglia 80x86 si è evoluta con la nascita di
nuove CPU a 16 bit e a 32 bit, sino alle attuali CPU a
64 bit. La Figura 7.3 mostra, ad esempio, un ingrandimento della struttura interna
della CPU Intel Pentium I; questa CPU (che viene considerata ormai vecchia)
integra al suo interno circa 3100000 transistor!
Cerchiamo ora di capire meglio il principio di funzionamento di una CPU; a tale
proposito analizziamo la Figura 7.4 che mostra una R.C. già presentata nel
precedente capitolo.
Come già sappiamo, attraverso le due linee di selezione possiamo far svolgere a questo
circuito 4 funzioni differenti; in particolare, si nota che:
- per S0 = 0 e S1 = 0 si ottiene in uscita il complemento a 1
del nibble in ingresso
- per S0 = 0 e S1 = 1 si ottiene in uscita lo stesso nibble in
ingresso.
- per S0 = 1 e S1 = 0 si ottiene in uscita il nibble 1111b
- per S0 = 1 e S1 = 1 si ottiene in uscita il nibble 0000b
Si può paragonare il circuito di Figura 7.4 ad una sorta di rudimentale CPU a
4 bit, dotata di 4 linee per il dato in ingresso, 4 linee per il
dato in uscita e 2 linee di selezione (linee di controllo) che permettono di
specificare una tra le 22=4 istruzioni eseguibili; ciascuna istruzione
per essere capita dalla CPU deve essere espressa come al solito sotto forma di
segnali logici e cioè, sotto forma di codice binario. Nel caso, ad esempio, di S0=0
e S1=0, il circuito di Figura 7.4 esegue l'istruzione NOT che consiste in
questo caso nella inversione dei 4 bit del dato in ingresso; possiamo dire
allora che in questa CPU l'istruzione NOT viene codificata con il codice
binario 00b. Il valore binario che codifica una determinata istruzione prende il
nome di codice macchina; l'insieme di tutti i codici macchina riconosciuti da una
CPU rappresenta, come è stato già anticipato, il set di istruzioni della
CPU stessa.
A questo punto appare chiaro il principio di funzionamento di una CPU; ciascuna
istruzione appartenente al programma da eseguire, viene codificata attraverso il relativo
codice macchina. L'esecuzione di una determinata istruzione consiste nell'invio alla
CPU della sequenza di segnali logici che codificano l'istruzione stessa; questi
segnali selezionano all'interno della CPU l'apposita R.C. che esegue
l'istruzione desiderata.
Tornando al circuito di Figura 7.4, supponiamo, ad esempio, di eseguire un programma
che ad un certo punto prevede una istruzione per l'inversione dei bit del nibble che si
trova in memoria all'indirizzo 01001111b; il codice macchina di questa istruzione
può essere allora:
00b 01001111b
L'esecuzione di questa istruzione si svolge in diverse fasi. Prima di tutto, l'istruzione
viene decodificata da un apposito circuito di controllo; il circuito di controllo dice
alla CPU di leggere dalla memoria un nibble che si trova all'indirizzo
01001111b; una volta che il nibble è stato caricato (attraverso le 4
linee di ingresso), il circuito di controllo invia il codice 00b alle linee di
selezione della CPU in modo da abilitare l'istruzione NOT. Alla fine
si ottiene in uscita il nibble in ingresso con i bit invertiti.
Le considerazioni appena esposte evidenziano anche il fatto che l'unico linguaggio
capito dalla CPU è, naturalmente, il codice macchina; nei capitoli successivi
vedremo però che fortunatamente la CPU può essere programmata anche attraverso
linguaggi molto più semplici e allo stesso tempo più evoluti.
7.4 La struttura generale di un computer
In base a ciò che è stato appena detto a proposito della macchina di Von Neumann
e del principio di funzionamento di una CPU, possiamo subito dedurre una serie di
considerazioni generali relative alla organizzazione interna di un computer; l'aspetto
più evidente riguarda il fatto che la CPU ha la necessità di comunicare con tutti
gli altri dispositivi del computer, che vengono chiamati periferiche. Tra le varie
periferiche, la più importante di tutte è senza dubbio la memoria del computer che viene
anche chiamata memoria centrale; proprio per questo motivo, quando si parla di
cuore del computer ci si riferisce all'insieme formato dalla CPU e dalla
memoria centrale.
Tutte le altre periferiche vengono trattate come secondarie e vengono anche chiamate
dispositivi di I/O (input/output); tra i vari dispositivi di I/O che
usualmente risultano collegati al computer si possono citare: tastiere, mouse, monitor,
stampanti, plotter, scanner, schede audio, schede video, joystick, hard disk, lettori
di floppy disk, lettori CD, etc. Esistono dispositivi accessibili, sia in lettura che
in scrittura (memoria centrale, hard disk, floppy disk), altri accessibili solo in
lettura (mouse, joystick) e altri ancora accessibili solo in scrittura (stampanti,
plotter).
La CPU dialoga con una qualsiasi periferica attraverso un interscambio di dati;
questo accade, ad esempio, quando la CPU deve accedere in lettura o in scrittura
alla memoria, oppure quando la CPU deve leggere le coordinate del cursore del
mouse sullo schermo, oppure quando la CPU deve visualizzare una immagine sullo
schermo, etc. Affinché sia possibile l'interscambio di dati, la CPU viene
connessa a tutte le periferiche attraverso una serie di linee elettriche che nel loro
insieme formano il cosiddetto Data Bus (bus dei dati); su ciascuna linea
elettrica del Data Bus transita uno dei bit del dato da trasferire.
Un altro aspetto abbastanza evidente riguarda il fatto che la CPU per poter
dialogare con una periferica deve chiaramente conoscerne l'indirizzo; nel caso della
memoria abbiamo già visto che le varie celle vengono identificate attraverso un
indirizzo rappresentato da un numero intero. Per tutte le altre periferiche si
utilizza lo stesso procedimento; ad ogni periferica viene associato quindi un
determinato numero intero che rappresenta l'indirizzo che identifica in modo univoco
la periferica stessa.
Possiamo dire quindi che nel momento in cui la CPU vuole dialogare con una
determinata periferica, deve prima di tutto specificare l'indirizzo a cui vuole
accedere; come al solito, questo indirizzo deve essere rappresentato sotto forma di
segnali logici e cioè, sotto forma di codice binario. A tale proposito la CPU
viene connessa a tutte le periferiche attraverso una serie di linee elettriche che
nel loro insieme formano il cosiddetto Address Bus (bus degli indirizzi); su
ciascuna linea elettrica dell'Address Bus transita uno dei bit del numero
binario che rappresenta l'indirizzo a cui la CPU vuole accedere.
Tutto il sistema appena descritto non potrebbe assolutamente funzionare se non venisse
coordinato da un apposito circuito di controllo; questo circuito rappresenta la cosiddetta
logica di controllo o Control Logic (CL) del computer. Il compito
fondamentale svolto dalla CL consiste nel gestire i vari dispositivi che formano
il computer stabilendo istante per istante quali dispositivi devono essere attivati e quali,
invece, devono essere disattivati.
Per avere un'idea dell'importanza della CL, supponiamo, ad esempio, che la CPU
debba leggere un dato dalla memoria per poi applicare ad esso l'istruzione NOT; in
questo caso la CL carica sull'Address Bus l'indirizzo di memoria a cui si
deve accedere e predispone la memoria stessa per una operazione di lettura. Terminata
questa fase la CL autorizza la CPU a leggere il dato dalla memoria attraverso
il Data Bus; una volta che la lettura è stata effettuata, la CL autorizza
l'invio alla CPU del codice macchina che abilita l'esecuzione dell'istruzione
NOT sul dato appena letto.
Per la corretta gestione di tutta questa situazione, la CPU viene connessa a tutte
le periferiche attraverso una serie di linee elettriche che nel loro insieme formano il
cosiddetto Control Bus (bus di controllo); sul Control Bus transitano dei
valori binari che codificano i vari segnali di controllo necessari per il coordinamento
di tutto il sistema.
Raccogliendo le considerazioni appena esposte, possiamo definire la struttura generale
che assume un classico computer appartenente alla piattaforma hardware basata sulle
CPU Intel 80x86 e compatibili; la Figura 7.5 illustra uno schema a blocchi che
comprende anche diverse periferiche collegate al computer.
Analizziamo innanzi tutto l'Address Bus che in Figura 7.5 è stato evidenziato con
il colore rosso; l'ampiezza dell'Address Bus e cioè, il numero di linee da cui
è composto, determina la quantità massima di memoria fisicamente indirizzabile dalla
CPU. Osserviamo, infatti, che su un Address Bus a n linee possono
transitare numeri binari formati da n bit (un bit per ogni linea); con n
bit possiamo rappresentare 2n numeri interi positivi distinti e cioè,
tutti i numeri compresi tra 0 e 2n-1. Complessivamente quindi
possiamo specificare gli indirizzi relativi a 2n celle di memoria
distinte; per conoscere la quantità massima di memoria fisica indirizzabile dalla
CPU dobbiamo quindi definire l'ampiezza in bit di ogni cella di memoria. Nelle
piattaforme hardware basate sulle CPU 80x86 è stato deciso di adottare l'ampiezza
di 8 bit (1 byte) per ogni cella di memoria; in definitiva, possiamo dire
che con un Address Bus a n linee, la CPU è in grado di accedere ad
un massimo di 2n byte di memoria fisica.
Le varie linee che compongono l'Address Bus vengono indicate per convenzione con
i simboli A0, A1, A2, A3, etc; il simbolo A0 indica
ovviamente la linea lungo la quale transita il bit meno significativo del numero binario
che codifica l'indirizzo a cui vogliamo accedere.
La tabella di Figura 7.6 illustra una serie di casi che si riferiscono a CPU
realmente esistenti; il codice 80586 indica in modo generico i vari modelli di
CPU riconducibili alla classe Pentium I.
Le considerazioni appena esposte si riferiscono all'indirizzamento della memoria centrale
del computer; ci si può chiedere come avvenga, invece, l'indirizzamento delle altre
periferiche. Come è stato già anticipato, anche i vari dispositivi di I/O
vengono indirizzati con la stessa tecnica utilizzata per la memoria centrale; ad ogni
dispositivo di I/O quindi viene assegnato un numero intero che ne rappresenta in
modo univoco l'indirizzo. La tastiera del computer, ad esempio, si trova all'indirizzo
esadecimale 60h; è compito della CL fare in modo che l'indirizzo di
una periferica secondaria non venga confuso con l'indirizzo di una cella della memoria
centrale. Nel caso in cui la CPU debba comunicare con la tastiera, la CL
abilita questa periferica e disabilita la memoria centrale; in questo modo l'indirizzo
60h inviato attraverso l'Address Bus mette in comunicazione la CPU
con la tastiera e non con la cella 60h della memoria centrale.
Ciascuna periferica secondaria è dotata di una memoria propria che nella gran parte
dei casi ammonta a pochi byte; questa piccola area di memoria viene chiamata porta
hardware. Un normale joystick a due assi e due pulsanti, ad esempio, utilizza una
memoria di appena 1 byte; attraverso questo byte il joystick fornisce alla
CPU tutte le informazioni relative allo stato (on/off) dei due pulsanti e alla
posizione x, y della leva.
Per indirizzare questa categoria di periferiche secondarie la CPU utilizza una
parte delle linee dell'Address Bus; con le vecchie CPU come l'8086
venivano utilizzate solo le prime 8 linee dell'Address Bus (da A0
a A7) con la possibilità quindi di gestire sino a 28=256
periferiche differenti. A partire dalle CPU 80386 vengono, invece, utilizzate le
prime 16 linee dell'Address Bus (da A0 a A15); in questo caso
è possibile gestire sino a 216=65536 periferiche differenti.
Esistono però anche periferiche secondarie particolari come la scheda video; anche le
schede video di vecchia generazione arrivano ad avere una memoria propria (memoria video)
che ammonta a qualche centinaio di Mb. Questa memoria ovviamente non può essere
indirizzata con la stessa tecnica delle porte hardware utilizzata per un joystick
o per un mouse; nel caso della memoria video (e nei casi analoghi) si ricorre allora ad
una tecnica che prende il nome di I/O memory mapped (input/output mappato nella
memoria centrale). Come si intuisce dal nome, questa tecnica consiste nel mappare nella
memoria centrale la porzione di memoria della periferica secondaria a cui si vuole accedere;
in sostanza, in una precisa area della memoria centrale viene creata una immagine della
porzione di memoria della periferica secondaria. Per accedere alla memoria della periferica
la CPU non deve fare altro che accedere all'immagine presente nella memoria centrale;
tutte le operazioni di I/O compiute dalla CPU su questa immagine si
ripercuotono istantaneamente sulla memoria della periferica.
Gli indirizzi di memoria inviati attraverso l'Address Bus vengono ricevuti
da un apposito circuito decodificatore che provvede a mettere in collegamento la
CPU con la cella di memoria desiderata; a questo punto può iniziare
l'interscambio di dati che naturalmente si svolge attraverso il Data Bus,
evidenziato in Figura 7.5 con il colore verde.
Le varie linee che compongono il Data Bus vengono indicate per convenzione con
i simboli D0, D1, D2, D3, etc; il simbolo D0 indica
ovviamente la linea lungo la quale passa il bit meno significativo del dato binario
che sta transitando sul Data Bus.
L'ampiezza del Data Bus e cioè, il numero di linee da cui è composto,
determina l'ampiezza massima in bit che possono avere i dati gestiti via hardware
dalla CPU; osserviamo, infatti, che su un Data Bus formato, ad esempio,
da 16 linee possono transitare numeri binari formati al massimo da 16
bit.
In base allora a quanto è stato esposto nei precedenti capitoli, possiamo dire che
l'ampiezza del Data Bus è un parametro importantissimo in quanto definisce
la cosiddetta architettura della CPU; una CPU con architettura
a n bit (cioè con Data Bus a n linee) è dotata di R.C.
in grado di eseguire via hardware operazioni logico aritmetiche su numeri binari a
n bit.
Nel caso, ad esempio, della CPU 80486, il Data Bus a 32 bit permette
la gestione via hardware di dati binari formati al massimo da 32 bit; se vogliamo
gestire dati binari a 64 bit, dobbiamo procedere via software scrivendo un apposito
programma che scompone ogni dato a 64 bit in gruppi da 32 bit.
Come conseguenza pratica delle cose appena dette, segue anche il fatto che l'ampiezza
in bit del Data Bus influisce sulle caratteristiche dei vari tipi di dati che
possiamo simulare via hardware con la CPU; nei precedenti capitoli abbiamo visto,
infatti, che con n bit possiamo rappresentare, ad esempio, tutti i numeri interi
senza segno compresi tra:
0 e 2n-1
e tutti i numeri interi con segno compresi tra:
-(2n-1) e +(2n-1-1)
La tabella di Figura 7.7 illustra una serie di casi che si riferiscono a CPU
realmente esistenti; in questa tabella vengono mostrati i limiti inferiore e
superiore dei numeri interi di ampiezza massima, con e senza segno, rappresentabili
dalla CPU in funzione del numero di linee del Data Bus. Nel caso della
80586, il Data Bus è internamente a 64 linee, mentre esternamente
alla CPU è formato da 32 linee.
Come si nota dalla Figura 7.7, raddoppiando il numero di linee del Data Bus si
verifica un enorme aumento dei numeri binari rappresentabili; osservando, infatti, che
con n bit possiamo formare 2n numeri binari diversi e con
2n bit possiamo formare 22n numeri binari diversi, possiamo dire
che passando da un Data Bus a n linee ad un Data Bus a 2n linee,
i numeri binari rappresentabili crescono di un fattore pari a:
22n / 2n = 2n
Naturalmente, tutto ciò comporta un notevole aumento della complessità circuitale in
quanto bisogna ricordare che una CPU con Data Bus a n linee deve
essere in grado di gestire numeri binari a n bit e, in particolare, deve essere
in grado di eseguire operazioni logico aritmetiche su numeri binari a n bit;
aumentare quindi il numero di linee del Data Bus significa dover aumentare in modo
considerevole le porte logiche delle R.C. che eseguono queste operazioni. Il
problema fondamentale che i progettisti devono affrontare, consiste nel riuscire ad
inserire nello spazio ristretto della CPU un numero di componenti elettronici
(transistor) che ormai supera abbondantemente i dieci milioni; la CPU AMD Athlon,
ad esempio, integra al suo interno circa 22000000 di transistor!
Torniamo ora alla Figura 7.5 per chiarire il significato dei termini che indicano i vari
dispositivi presenti nel computer.
7.4.1 Memoria RAM
Il dispositivo indicato in Figura 7.5 con la sigla RAM rappresenta la memoria centrale
del computer; la sigla RAM sta per Random Access Memory (memoria ad accesso
casuale). Il termine casuale si riferisce al fatto che il tempo necessario alla CPU
per accedere ad una qualsiasi cella di memoria è indipendente dalla posizione (indirizzo)
della cella stessa; la CPU quindi per accedere ad una qualsiasi cella impiega un
intervallo di tempo costante. Questa situazione che si presenta nelle memorie ad accesso
casuale è opposta al caso delle memorie ad accesso sequenziale (come le memorie a
nastro) dove il tempo di accesso dipende dalla posizione in cui si trova il dato; nel caso,
ad esempio, delle memorie a nastro (come le cassette che si utilizzavano con i micro
computer Amiga e ZX Spectrum), per accedere ad un dato registrato nella parte
iniziale del nastro è necessario un tempo brevissimo, mentre per accedere ad un dato
registrato nella parte finale del nastro è necessario un tempo lunghissimo dovuto alla
necessità di far scorrere l'intero nastro.
La memoria RAM è accessibile, sia in lettura, sia in scrittura; come vedremo nel
prossimo capitolo, anche le memorie RAM vengono realizzate con i transistor. Il
contenuto della memoria RAM permane finché il computer rimane acceso; non appena
il computer viene spento, viene a mancare l'alimentazione elettrica e il contenuto della
RAM viene perso.
7.4.2 Memoria ROM
Il dispositivo indicato in Figura 7.5 con la sigla ROM è una memoria del tutto
simile alla RAM e si differenzia per il fatto di essere accessibile solo in
lettura; la sigla ROM, infatti, sta per Read Only Memory (memoria a sola
lettura). Il contenuto della memoria ROM viene inserito in modo permanente in
un apposito chip montato sul computer; questo significa che quando si spegne
il computer, la memoria ROM conserva le sue informazioni.
All'interno della ROM troviamo una serie di programmi scritti in Assembly
che assumono una importanza vitale per il computer; vediamo, infatti, quello che succede
ogni volta che un PC viene acceso. Non appena si accende il computer, una parte
della memoria ROM contenente svariati programmi viene mappata nella memoria
RAM; il contatore della CPU viene inizializzato con l'indirizzo della
RAM da cui inizia uno di questi programmi, chiamato POST. Possiamo dire
quindi che all'accensione del computer, la prima istruzione in assoluto eseguita dalla
CPU è quella che avvia il programma POST; la sigla POST sta per
Power On Self Test (autodiagnosi all'accensione) e indica un programma che
esegue una serie di test diagnostici all'accensione del computer, per verificare che
tutto l'hardware sia funzionante. Qualsiasi problema incontrato in questa fase, viene
segnalato attraverso messaggi sullo schermo o (se il problema riguarda proprio lo
schermo) attraverso segnali acustici; se, ad esempio, si accende il computer con la
tastiera staccata (o danneggiata), il POST stampa sullo schermo un messaggio del
tipo:
Keyboard or System Unit Error
Se il POST si conclude con successo, vengono raccolte una serie di importanti
informazioni sull'hardware del computer che vengono poi memorizzate in una apposita area
della RAM e in una particolare memoria chiamata CMOS Memory; tutti questi
argomenti vengono trattati in dettaglio nella sezione Assembly Avanzato.
Al termine del POST vengono inizializzati diversi dispositivi hardware e vengono
caricati in RAM una serie di "mini programmi" (procedure) scritti in
Assembly, che permettono di accedere a basso livello alle principali risorse
hardware del computer; nel loro insieme queste procedure rappresentano il BIOS o
Basic Input Output System (sistema primario per l'input e l'output). Le procedure
del BIOS permettono, ad esempio, di formattare hard disk e floppy disk, di inviare
dati "grezzi" alla stampante, di accedere alla tastiera, al mouse, etc; tutte queste
procedure assumono una importanza fondamentale in quanto vengono utilizzate dai sistemi
operativi (SO) come il DOS, per implementare numerosi servizi che permettono
agli utenti di lavorare con il computer. I moderni SO come Windows,
Linux, MacOSX, etc, usano propri servizi, molto più sofisticati, in quanto
quelli del BIOS risultano insufficienti.
L'ultimo importantissimo compito svolto in fase di avvio dai programmi contenuti nella
ROM, consiste nel bootstrap e cioè, nella ricerca di un particolare
programma contenuto nel cosiddetto boot sector (settore di avvio); il termine
boot sector indica i primi 512 byte di un supporto di memoria come un
floppy disk, un hard disk o un CD-ROM. Nei moderni PC il bootstrap cerca
il boot sector scandendo in sequenza il primo lettore floppy disk, il primo
lettore CD e infine l'hard disk; se la ricerca fornisce esito negativo, il computer si
blocca mostrando un messaggio di errore che indica l'assenza del SO. La ricerca
si conclude, invece, con esito positivo se nei primi 512 byte di uno dei supporti
di memoria citati in precedenza viene trovato un programma chiamato boot loader
(caricatore di avvio); in questo caso il boot loader viene caricato in memoria
e viene fatto eseguire dalla CPU. Il compito fondamentale del boot loader
consiste nel caricare nella memoria RAM il SO installato sul computer; a
questo punto i programmi di avvio della ROM hanno concluso il loro lavoro e il
controllo passa al SO.
7.4.3 Interfaccia tra la CPU e le periferiche
Analizzando la Figura 7.5 si nota che mentre, ad esempio, la RAM è connessa in modo
diretto alla CPU, altrettanto non accade per molte altre periferiche secondarie;
questa situazione è dovuta al fatto che esistono periferiche di tipo digitale e
periferiche di tipo analogico. La RAM è una periferica di tipo digitale in
quanto gestisce direttamente segnali logici che rappresentano dati binari; anche la
CPU è ovviamente un dispositivo di tipo digitale e quindi possiamo dire che
la CPU e la RAM parlano lo stesso linguaggio. Tutto ciò rende possibile
un interscambio diretto di dati tra CPU e RAM attraverso il Data
Bus; questo aspetto è fondamentale in quanto la RAM deve essere in grado di
fronteggiare l'elevatissima velocità operativa della CPU.
Esistono, invece, numerose periferiche di tipo analogico che in quanto tali non possono
essere collegate direttamente alla CPU; una periferica di tipo analogico parla,
infatti, un linguaggio differente da quello binario parlato dalla CPU.
Consideriamo, ad esempio, un normale joystick dotato di due assi (x, y) e
due pulsanti; lo stato on/off di ciascun pulsante viene rappresentato attraverso
una tensione elettrica. Possiamo associare il valore di tensione V0 allo stato
off e il valore di tensione V1 allo stato on; questi valori analogici
di tensione per poter essere letti dalla CPU devono essere prima convertiti in
livelli logici compatibili con quelli usati dalla CPU stessa. Possiamo convertire,
ad esempio, il valore V0 nel valore di tensione GND utilizzato dalla
CPU per rappresentare il livello logico 0; analogamente, possiamo convertire
il valore V1 nel valore di tensione +Vcc utilizzato dalla CPU per
rappresentare il livello logico 1.
Per gli assi del joystick la situazione è più complessa; le coordinate x,
y che esprimono la posizione della leva, sono rappresentate dai valori assunti
da due resistenze elettriche variabili (reostati). È chiaro che la CPU non può
essere in grado di leggere direttamente i valori analogici in ohm di queste due
resistenze; per poter effettuare questa lettura bisogna prima convertire i due valori
di resistenza in due numeri binari.
Un esempio ancora più emblematico è rappresentato dal modem che, come si sa,
viene utilizzato per permettere a due o più computer di comunicare tra loro attraverso
le linee telefoniche; il problema che si presenta è dato dal fatto che molte linee
telefoniche sono ancora di tipo analogico e quindi possono accettare solamente segnali
elettrici analogici. Per gestire questa situazione viene utilizzato appunto il modem
che ha il compito di effettuare le necessarie conversioni da digitale ad analogico e
viceversa.
In fase di trasmissione il modem converte i segnali logici che arrivano dalla
CPU in segnali analogici da immettere nelle linee telefoniche; in fase di ricezione
il modem converte i segnali analogici che arrivano dalle linee telefoniche in
segnali logici destinati alla CPU. La conversione in trasmissione viene chiamata
modulazione, mentre la conversione in ricezione viene chiamata demodulazione;
dalla unione e dalla contrazione di questi due termini si ottiene il termine modem.
Per effettuare queste conversioni vengono utilizzati diversi metodi; la Figura 7.8 illustra,
ad esempio, un metodo di conversione che viene chiamato modulazione di ampiezza.
La Figura 7.8a mostra la rappresentazione logica del numero binario 01010011b; la
Figura 7.8b mostra, invece, la rappresentazione analogica dello stesso numero, ottenuta
attraverso la modulazione di ampiezza; in pratica, i vari livelli logici che formano
il numero binario, vengono convertiti in un segnale elettrico oscillante, con l'ampiezza
(altezza) delle varie oscillazioni che è funzione dei livelli logici stessi. Come si può
notare, il livello logico 0 viene convertito in una oscillazione avente una
determinata ampiezza; il livello logico 1 viene convertito in una oscillazione
avente ampiezza maggiore.
Tutte le periferiche di tipo analogico devono essere collegate alla CPU attraverso
appositi dispositivi che provvedono alle necessarie conversioni da analogico a digitale e
viceversa; questi dispositivi vengono genericamente chiamati interfacce hardware.
L'obiettivo che i produttori di hardware si prefiggono è quello di realizzare periferiche
di tipo digitale che evitando queste conversioni, semplificano enormemente le comunicazioni
con la CPU; è chiaro, infatti, che eliminando la complessa fase di conversione dei
segnali, si ottiene un notevole aumento delle prestazioni generali del computer.
7.5 Un esempio reale: la CPU Intel 8080
Per chiarire il significato degli altri dispositivi visibili in Figura 7.5 e per capire
meglio il funzionamento di un computer, analizziamo un esempio reale rappresentato da
un computer basato sulla CPU Intel 8080; questa CPU appartiene ormai alla
preistoria, ma come vedremo nei capitoli successivi, il suo "fantasma" aleggia ancora
persino sulle CPU di classe Pentium. La Figura 7.9 illustra uno schema a
blocchi con la cosiddetta piedinatura della CPU 8080; la piedinatura
rappresenta l'insieme dei terminali elettrici che collegano una CPU (o un
generico chip) al mondo esterno.
Osserviamo subito che questa CPU è formata da tre chip che rappresentano
il generatore di clock 8224, la CPU vera e propria (8080) e la
logica di controllo 8228; si nota anche la presenza sui tre chip del
terminale di massa GND e delle tensioni di alimentazione +5V, -5V e
+12V.
Come è stato già detto in precedenza, l'8080 è una CPU con architettura
a 8 bit e dispone di un Address Bus a 16 linee con la possibilità
quindi di indirizzare fino a 216=65536 byte di RAM fisica; in
Figura 7.9 si nota, infatti, in modo evidente la presenza delle 8 linee del Data
Bus (da D0 a D7) e delle 16 linee dell'Address Bus (da
A0 a A15).
Nella parte inferiore del lato destro del chip 8228 (System Control) notiamo
la presenza del Control Bus a 5 linee; su queste 5 linee transitano
i segnali di controllo chiamati INTA, MEMR, MEMW, I/OR e
IO/W. La linea MEMR abilita una operazione di lettura in RAM; la sigla
MEMR significa, infatti, Memory Read. La linea MEMW abilita una operazione
di scrittura in RAM; la sigla MEMW significa, infatti, Memory Write. La
linea I/OR abilita una operazione di lettura da un dispositivo di I/O; la sigla
I/OR significa, infatti, I/O Read. La linea I/OW abilita una operazione di
scrittura in un dispositivo di I/O; la sigla I/OW significa, infatti, I/O
Write.
7.5.1 Le interruzioni hardware
Passiamo ora alla linea di controllo INTA che svolge un ruolo veramente importante;
questa linea opera in combinazione con l'uscita INTE e l'ingresso INT visibili
sul lato sinistro del chip 8080. I segnali che transitano su queste linee hanno lo
scopo di permettere alle varie periferiche di richiedere la possibilità di comunicare con
la CPU; per permettere alle periferiche di poter dialogare con la CPU, si
possono utilizzare due tecniche principali che vengono chiamate polling (sondaggio)
e hardware interrupts (interruzioni hardware).
Con la tecnica del polling la CPU interroga (sonda) continuamente tutte le
periferiche per sapere se qualcuna di esse vuole intervenire; l'eventuale richiesta di
intervento viene inviata da ogni periferica attraverso appositi segnali logici. Il vantaggio
fondamentale della tecnica del polling consiste nella sua semplicità che si traduce
quindi in una conseguente semplificazione circuitale; lo svantaggio evidente è rappresentato,
invece, dal grave rallentamento generale del sistema dovuto al fatto che la CPU è
costantemente impegnata nelle operazioni di sondaggio delle varie periferiche. La tecnica
del polling veniva largamente utilizzata nei vecchi computer; in effetti, in passato
questa tecnica si rivelava vantaggiosa grazie anche al fatto che esistevano pochissime
periferiche da collegare ai computer.
Nei moderni computer e, in particolare, in tutti i PC appartenenti alla piattaforma
hardware 80x86 viene utilizzata, invece, la sofisticata tecnica delle hardware
interrupts; questa tecnica consiste semplicemente nel fatto che se una periferica vuole
dialogare con la CPU, deve essere essa stessa a segnalare la richiesta.
A tale proposito, su qualsiasi PC basato sulle CPU 80x86 è presente almeno
un chip chiamato 8259 PIC; la sigla PIC sta per Programmable
Interrupts Controller (controllore programmabile delle interruzioni). Il compito
fondamentale del PIC è quello di ricevere tutte le richieste di intervento che
arrivano dalle varie periferiche; il PIC provvede anche a disporre queste richieste
in una apposita coda di attesa. Per abilitare la gestione delle hardware interrupts
la CPU 8080 si serve dell'apposita linea INTE visibile in Figura 7.9; la sigla
INTE sta, infatti, per interrupts enable (abilitazione delle interruzioni).
In fase di avvio del computer vengono installate in RAM una serie di procedure
scritte in Assembly che vengono chiamate ISR; la sigla ISR sta per
Interrupt Service Routine (procedura per la gestione di una interruzione). Come
si deduce dal nome, il compito delle ISR è quello di rispondere alle richieste di
intervento che arrivano dalle varie periferiche; gli indirizzi di memoria relativi alle
varie ISR vengono sistemati in una apposita area della RAM e formano i
cosiddetti Interrupt Vectors (vettori di interruzione). Diverse ISR
vengono installate da un apposito programma della ROM e rappresentano le procedure
del BIOS citate in precedenza; numerose altre ISR vengono installate dai
SO.
In base alle considerazioni appena esposte, analizziamo ora quello che succede quando una
periferica vuole dialogare con la CPU; vediamo, in particolare, quello che succede
quando l'utente preme un tasto sulla tastiera mentre la CPU sta eseguendo un
programma:
- Mentre un programma è in esecuzione, l'utente preme un tasto sulla tastiera.
- L'hardware della tastiera salva lo
Scan Code del tasto in un
apposito buffer (area di memoria di una periferica dove si accumulano i dati
in transito) e invia un segnale al PIC; questo segnale prende il
nome di Interrupt Request o IRQ (richiesta di interruzione).
- L'IRQ inviato dalla tastiera viene ricevuto (insieme ad altre IRQ
di altre periferiche) dal PIC; le varie IRQ vengono disposte dal
PIC nella coda di attesa e vengono ordinate in base alla loro priorità.
Il PIC provvede poi ad inviare alla CPU la IRQ che si trova
in cima alla coda di attesa.
- La CPU riceve la IRQ attraverso la linea INT visibile sul
lato sinistro del chip 8080 di Figura 7.9; a questo punto la CPU
porta a termine l'istruzione che stava elaborando, sospende immediatamente il
relativo programma e invia al PIC un segnale di via libera; questo
segnale viene inviato attraverso la linea INTA (Interrupt
Acknowledgement) visibile nel Control Bus di Figura 7.9. Il fatto che
il programma in esecuzione venga temporaneamente interrotto giustifica la
definizione di interruzione hardware.
- Il PIC riceve il segnale di via libera e invia alla CPU
attraverso il Data Bus il codice che identifica la periferica che vuole
intervenire; questo codice non è altro che l'indice che individua negli
Interrupt Vectors l'indirizzo della ISR da chiamare.
- L'ISR appena chiamata provvede a soddisfare le richieste della periferica
che ha inviato l'IRQ; nel caso della pressione di un tasto sulla tastiera,
viene chiamata una ISR che legge dal buffer della tastiera il codice del
tasto premuto e lo mette a disposizione dei programmi. Terminate le varie
elaborazioni l'ISR segnala alla CPU di aver concluso il suo lavoro.
- La CPU provvede a ripristinare il programma precedentemente interrotto; a
questo punto la gestione della interruzione è terminata.
Come si può facilmente intuire, il metodo delle Hardware Interrupts è sicuramente
più complesso della tecnica del polling, ma presenta il vantaggio di garantire una
gestione enormemente più efficiente delle periferiche; è chiaro, infatti, che grazie alla
tecnica delle interruzioni hardware, la CPU dialoga con le periferiche solo quando
è strettamente necessario evitando in questo modo inutili perdite di tempo.
7.5.2 L'accesso diretto alla memoria RAM
Nel caso generale, qualsiasi elaborazione svolta dal computer deve avvenire rigorosamente
sotto la supervisione della CPU; esiste però un caso per il quale l'intervento
della CPU è del tutto superfluo e provoca anche un notevole rallentamento delle
operazioni. Questo caso si verifica quando dobbiamo semplicemente trasferire un grosso
blocco di dati dalla RAM ad una periferica di I/O o viceversa; in una
situazione del genere, non viene eseguita alcuna operazione logico aritmetica, per cui
l'intervento della CPU è del tutto inutile.
Queste considerazioni hanno spinto i progettisti dei computer a prevedere l'eventualità
di far comunicare determinate periferiche direttamente con la RAM, aggirando in
questo modo la CPU; l'interscambio diretto di dati tra RAM e periferiche
rende questa operazione nettamente più veloce ed efficiente.
Nelle piattaforme hardware 80x86 l'accesso diretto alla RAM da parte delle
periferiche viene gestito da un apposito chip chiamato 8237 DMAC; la sigla
DMAC sta per Direct Memory Access Controller (controllore per l'accesso
diretto alla memoria). Questo chip è una vera e propria mini CPU che è
in grado però di eseguire esclusivamente trasferimenti di dati tra RAM e
periferiche; nei moderni PC il chip 8237 è stato integrato direttamente nei
circuiti del computer.
In Figura 7.5 vediamo il controllore DMA che si trova posizionato nel computer
proprio come se fosse una CPU; quando una periferica vuole scambiare dati
direttamente con la RAM, deve comunicarlo al DMAC. In altre parole, è
necessario innanzi tutto programmare il DMAC in modo da fornirgli le necessarie
informazioni che riguardano la periferica che vuole accedere direttamente in RAM,
quanti byte di dati devono essere trasferiti, etc; il DMAC una volta programmato
invia la necessaria richiesta alla CPU attraverso la linea DMA Request
visibile in Figura 7.9 sul lato sinistro del chip 8080 (questa richiesta viene
anche chiamata HOLD). Se la CPU accetta la richiesta, invia un segnale
di via libera attraverso la linea HLDA (HOLD Acknowledgement) visibile
in Figura 7.9 sul lato destro del chip 8080; a questo punto la CPU si
disattiva e cede il controllo del Data Bus al DMAC.
Generalmente il DMAC suddivide il Data Bus in gruppi di 8 linee
chiamati DMA Channels (canali DMA); sulle CPU con Data Bus
a 32 linee, ad esempio, abbiamo 4 canali DMA chiamati: channel
0 (linee da D0 a D7), channel 1 (linee da D8 a
D15), channel 2 (linee da D16 a D23) e channel 3
(linee da D24 a D31).
Solamente alcune periferiche sono predisposte per l'accesso diretto in RAM; tra
queste periferiche si possono citare gli hard disk, i lettori di floppy disk, i lettori
di CD/DVD e le schede audio. Per avere un'idea della notevole efficienza del DMA,
si può considerare proprio il caso della visione di un film in DVD sul computer;
in presenza di un lettore DVD con supporto per il DMA è possibile avere
una riproduzione estremamente fluida del film anche su computer relativamente lenti.
Molti SO permettono all'utente la disattivazione del DMA sul proprio
lettore DVD; in questo modo si può constatare che la riproduzione dei film in
DVD subisce un notevole rallentamento con evidenti salti tra un fotogramma e
l'altro.
7.5.3 Il segnale di clock
Il funzionamento del computer sarebbe impossibile se non si provvedesse a sincronizzare
perfettamente tutti i suoi componenti; la logica di controllo del computer, infatti, non
sarebbe in grado di sapere, ad esempio, se una determinata operazione aritmetica è già
stata eseguita dalla CPU, se un dato inviato alla RAM è già stato
memorizzato, se una periferica ha eseguito un determinato compito, etc.
Per ottenere la sincronizzazione tra tutti i componenti del computer viene utilizzato un
apposito segnale al quale viene affidato in pratica il compito di scandire il ritmo di
lavoro; i segnali più adatti per svolgere questa funzione sono i cosiddetti segnali
periodici. La Figura 7.10 illustra due esempi di segnali periodici; in Figura 7.10a
vediamo un segnale periodico di tipo analogico, mentre in Figura 7.10b vediamo un segnale
periodico di tipo logico.
Si definisce periodico un segnale i cui valori si ripetono ciclicamente nel tempo;
in pratica, un segnale periodico varia assumendo dei valori che si ripetono identicamente
ad intervalli regolari di tempo. Ciascuno di questi intervalli regolari di tempo viene
chiamato periodo; come si vede in Figura 7.10, il periodo di un segnale periodico
viene convenzionalmente indicato con la lettera T.
Ciascuna sequenza di valori che si sviluppa in un periodo T viene chiamata
ciclo; il numero di cicli completi che si svolgono nel tempo di 1 secondo
rappresenta la frequenza del segnale (f). Utilizzando le proporzioni
possiamo dire allora che:
1 ciclo sta a T secondi come f cicli stanno a 1 secondo
Da questa proporzione si ricava:
f = 1 / T
La frequenza quindi è l'inverso del periodo e di conseguenza la sua unità di misura
è sec-1; in onore del fisico tedesco Hertz, scopritore delle
onde radio, l'unità di misura della frequenza è stata chiamata hertz ed ha per
simbolo Hz. In elettronica si usano spesso i multipli: kHz (migliaia di
Hz), MHz (milioni di Hz), GHz (miliardi di Hz).
La sincronizzazione tra tutti i componenti che formano un computer viene ottenuta
attraverso un segnale periodico di tipo logico come quello visibile in Figura 7.10b; questo
segnale viene anche chiamato clock (orologio). Possiamo dire quindi che il segnale
di clock di una CPU è un segnale periodico che oscilla continuamente tra il livello
logico 0 e il livello logico 1. La frequenza di oscillazione del segnale
di clock di una CPU viene definita frequenza di clock; come molti sanno, la
frequenza di clock è un parametro fondamentale per una CPU in quanto determina la
cosiddetta frequenza di lavoro della CPU stessa. Quando si parla, ad esempio,
di CPU Athlon a 1800 MHz, ci si riferisce al fatto che questa particolare
CPU riceve un segnale di clock che compie 1800000000 cicli al secondo
(Hz); se si considera il fatto che tutte le CPU, a partire dall'80386
a 33 MHz, sono in grado di compiere una operazione di I/O in RAM in un
solo ciclo di clock, si può capire che in linea di principio, maggiore è la frequenza di
clock, maggiore sarà la velocità operativa del computer.
Il segnale di clock che sincronizza il computer deve avere come caratteristica fondamentale
una perfetta stabilità nel tempo; il modo migliore per ottenere questa caratteristica
consiste nello sfruttare una proprietà naturale del quarzo (e di altri materiali) chiamata
piezoelettricità. In pratica, tagliando in modo opportuno un cristallo di quarzo, si
ottiene una lamina che, sottoposta a pressione lungo una precisa direzione, sviluppa una
differenza di potenziale elettrico (tensione); sottoponendo la lamina di quarzo a trazione
lungo la stessa direzione, si sviluppa una differenza di potenziale elettrico con polarità
invertite rispetto al caso precedente. In generale, sottoponendo la lamina a continue pressioni
e trazioni (vibrazioni), si produce nella lamina stessa una tensione elettrica alternata;
l'aspetto importante è che questo fenomeno è reversibile, nel senso che sottoponendo la
lamina ad una tensione elettrica alternata (la cui polarità si inverte cioè ad intervalli
di tempo regolari), si produce nella lamina stessa una vibrazione ad altissima frequenza,
perfettamente stabile nel tempo. Appositi circuiti elettronici, chiamati oscillatori al
quarzo, convertono queste vibrazioni in un segnale periodico altamente stabile; nel caso
del computer, l'oscillatore produrrà un segnale periodico di tipo logico, che oscillerà
continuamente tra i valori 0 e 1, compatibili con i livelli logici della
CPU. In Figura 7.5 e in Figura 7.9 si può osservare il simbolo grafico che rappresenta
il cristallo di quarzo utilizzato dall'oscillatore; negli schemi elettrici questo cristallo
viene sempre indicato con la sigla XTAL.
Nel caso più generale i computer dispongono di un clock generator (generatore
di segnale di clock) che produce in uscita un unico segnale di clock da inviare alla
CPU; in alcuni casi, invece, il clock generator produce due segnali di
clock che hanno la stessa frequenza, ma risultano sfasati tra loro. Questo è proprio
quello che accade con la CPU 8080 visibile in Figura 7.9; in ogni caso, il segnale di
clock singolo o doppio viene utilizzato per ricavare altri segnali periodici destinati a
svolgere diversi compiti di sincronizzazione.
Per chiarire meglio questi concetti, facciamo riferimento proprio al doppio segnale di
clock prodotto in uscita dal clock generator 8224 della CPU 8080 di Figura
7.9; in questo caso si viene a creare la situazione mostrata in Figura 7.11.
I due segnali indicati con CLK1 e CLK2 vengono generati dal chip 8224
ed hanno la funzione di segnali di riferimento; come si può notare, questi due segnali
hanno la stessa frequenza f0 (e quindi lo stesso periodo T0), ma risultano
sfasati tra loro di mezzo periodo (180 gradi). Sovrapponendo questi due segnali
(applicandoli, ad esempio, ad una porta OR a due ingressi) la CPU ricava un
nuovo segnale che in Figura 7.11 viene indicato con CLKe; questo segnale ha quindi
frequenza:
fe = 2 * f0
e di conseguenza il suo periodo è:
Te = T0 / 2
Questo significa che nell'intervallo di tempo impiegato da CLK1 per compiere un
ciclo completo, CLKe compie due cicli completi.
CLKe ha un significato molto importante in quanto il suo periodo rappresenta il
cosiddetto intervallo di tempo elementare della CPU; si tratta cioè
dell'intervallo di tempo minimo, necessario alla CPU per eseguire le operazioni
hardware di base come l'abilitazione della memoria, l'abilitazione di un bus etc. È chiaro
che in teoria sarebbe vantaggioso spingere il più in alto possibile il valore della
frequenza fe; nella pratica però bisogna fare i conti con il tempo di risposta
delle porte logiche che limita il valore massimo di fe.
Sempre dalla Figura 7.11 si nota che a partire ugualmente dai due segnali di riferimento,
la CPU ricava un ulteriore segnale periodico CLKm; nel caso di Figura 7.11
questo segnale ha una frequenza di clock:
fm = f0 / 2
e ovviamente, periodo:
Tm = 2 * T0
Anche CLKm ha una grande importanza per la CPU in quanto ogni suo ciclo
rappresenta il cosiddetto ciclo macchina e più cicli macchina formano il
ciclo istruzione, cioè il numero di cicli macchina necessari alla CPU per
eseguire una determinata istruzione; ogni istruzione appartenente ad una CPU
viene eseguita in un preciso numero di cicli macchina e questo permette alla logica
di controllo di sincronizzare tutte le fasi necessarie per l'elaborazione dell'istruzione
stessa.
Nei manuali e nella documentazione tecnica relativa ai vari modelli di CPU, il numero
di cicli del segnale CLK1 (o CLK2) necessari per eseguire una determinata
istruzione, viene indicato con la definizione di clock cycles (cicli di clock).
Con il passare degli anni il progresso tecnologico sta portando alla realizzazione di
dispositivi elettronici sempre più veloci che permettono alle nuove CPU di lavorare
con frequenze di clock sempre più elevate; attraverso poi l'individuazione di algoritmi di
calcolo sempre più efficienti, è possibile realizzare R.C. capaci di eseguire le
istruzioni in un numero sempre minore di cicli di clock.
Per fare un esempio pratico, l'8086 ha una frequenza di clock di circa 5 MHz
ed esegue una moltiplicazione tra numeri interi in oltre 100 cicli di clock pari a:
100 / 5000000 = 0.00002 secondi = 20000 nanosecondi
(1 nanosecondo = 1 miliardesimo di secondo).
L'80486 ha una frequenza di clock di 33 MHz e per la stessa operazione richiede
poco più di 10 cicli di clock pari a:
10 / 33000000 = 0.0000003 secondi = 300 nanosecondi
In sostanza, l'80486 esegue una moltiplicazione 83 volte più velocemente
rispetto all'8086!