ARCHITETTURA DI UN ELABORATORE ELETTRONICO Il termine “architettura” riferito ai calcolatori indica l’organizzazione logica dei loro componenti interni e le modalità in cui essi cooperano in modo armonioso per eseguire operazioni più o meno complesse. Pertanto l’architettura di un computer può essere dedotta dalla conoscenza della struttura interna e dal modo in cui è possibile fare cooperare le unità fisiche tramite un repertorio di comandi, detti istruzioni, che definiscono il linguaggio della macchina. Funzionamento della macchina di von Neumann I moderni calcolatori elettronici, dai compatti personal computer ai grandi server di Internet, funzionano tutti in base al principio del programma memorizzato, enunciato per la prima volta nel 1945 dal matematico John von Neumann. Secondo questo principio, il computer deve contenere al suo interno le istruzioni sulle operazioni da eseguire - il programma - e i dati su cui esse operano. Solo in un secondo momento viene eseguito l’intero calcolo, senza necessità di intervento da parte dell’uomo. Pertanto in ogni computer è presente: • una memoria centrale, che è un dispositivo in grado di contenere le istruzioni costituenti il programma, i dati su cui operano e i risultati intermedi e finali dei calcoli; • una unità centrale di elaborazione o CPU (da Central Processing Unit), che è il blocco funzionale che esegue le elaborazioni; • delle interfacce di ingresso/uscita (I/U), collegate alla CPU, che consentono al computer rispettivamente di acquisire informazioni dall’ambiente esterno e di fornirgliene. L’unità centrale è poi collegata con le varie sezioni del computer mediante linee di comunicazione dette bus. La maggior parte dei componenti di un computer si trova oggi su un’unica scheda di circuito stampato, detta scheda madre o di sistema. Essa offre un supporto meccanico e un collegamento elettrico ai diversi componenti elettronici, tramite tracce conduttive incise su lamine di rame e depositate su un substrato isolante. Memoria centrale La memoria centrale è suddivisa, dal punto di vista funzionale, in una memoria di sola lettura o ROM (da Read Only Memory), e in una di lettura e scrittura o RAM (da Random Access Memory). Attualmente è realizzata con circuiti a semiconduttore, secondo una delle tecnologie seguenti: • TTL (da Transistor-Transistor Logic) • ECL (da Emitter-Coupled Logic) • n-MOS o c-MOS. La ROM è una memoria permanente, di sola lettura, programmata direttamente in fabbrica e non modificabile dall’utente. Essa contiene i programmi di sistema, detti anche servizi base di ingresso/uscita o BIOS (da Basic Input/Output Services), per cui è detta anche ROM-BIOS. I BIOS eseguono le operazioni elementari del computer, consentono di comunicare con i componenti hardware del sistema e svolgono un lavoro di supervisione e supporto, fornendo i servizi essenziali necessari ai programmi applicativi. In particolare essi si suddividono in tre categorie principali: 1. programmi eseguiti in fase di accensione per controllare tutti i componenti hardware presenti, operazione detta autotest all’accensione o POST (da Power On Self-Test), e per inizializzare registri e parametri; sono queste routine che determinano il ritardo che si verifica tra il momento in cui si accende il computer e il momento in cui si può iniziare a lavorare; 2. programma di caricamento del sistema operativo dal disco di avvio (di solito un disco fisso); 3. programmi che forniscono un controllo preciso e dettagliato delle varie componenti del computer, quali le periferiche di I/O e le unità disco. Nei primi personal computer IBM la memoria ROM conteneva anche l’interprete del linguaggio di programmazione BASIC, che veniva attivato all’accensione e costituiva il solo ambiente operativo disponibile. Dal punto di vista fisico, la memoria ROM è costituita da una matrice di celle che contengono i bit di informazione e dai circuiti di decodifica e selezione necessari per estrarre l’informazione da una o più celle, a seconda della lunghezza di parola della memoria (1, 4 od 8 bit, l’ultimo valore essendo il più comune). Supponiamo di volere realizzare una ROM costituita dalle seguenti 8 parole di 4 bit: Dal punto di vista concettuale, potremmo realizzare una griglia di fili conduttori da 8 righe e 4 colonne, e codificare ciascun 1 con un contatto elettrico, e ciascuno 0 con un isolamento agli incroci dei fili: In pratica, conviene realizzare i contatti inserendo dei diodi alimentati in modo opportuno nei punti dei contatti elettrici (cioè dove vanno memorizzati gli 1), ottenendosi un codificatore a matrice di diodi. Naturalmente, una volta realizzata o scritta, una ROM deve poi essere letta. Per questa operazione è sufficiente, in linea di principio, inviare un segnale di tensione nella riga che si vuole leggere, e rilevare su quali fili di colonna si presenti un segnale in uscita. In pratica la riga da leggere riceve la tensione dall’uscita di una porta AND a 3 ingressi, che costituisce la sezione finale di un decodificatore di riga. La selezione della porta AND di volta in volta attiva (che cioè deve produrre un segnale in uscita) viene effettuata inviandole in ingresso tre segnali di tensione (cioè tre bit 1). I tre ingressi di ciascuna porta sono costituiti dalle otto combinazioni che si possono ottenere dai tre bit forniti dalle tre linee di indirizzo A0, A1, A2 in ingresso al decodificatore. Naturalmente, solo la porta che riceve la combinazione di tre bit 1 produce un segnale in uscita. In tal modo, nelle quattro linee di uscita Y1, Y2, Y3, Y4 si rilevano segnali di tensione in corrispondenza dei bit 1 (cioè dei diodi) della riga letta. La precedente memoria ROM ha quindi la seguente tavola di verità: Memoria di lettura e scrittura (RAM). A differenza della ROM, la memoria di lettura e scrittura è di tipo volatile, in quanto perde i dati memorizzati al cessare dell’alimentazione. La sigla RAM sta per memoria ad accesso casuale, sebbene la prima dicitura sia più pertinente, in quanto anche la memoria ROM, dal punto di vista dell’accesso, è una memoria ad accesso casuale. Nei personal computer la RAM ha una capacità di 512-1.024 Megabyte, e può essere realizzata secondo diverse tecnologie: DRAM, SRAM, NOVRAM o intermedie tra esse. Memoria RAM dinamica (DRAM). La memoria RAM dinamica o DRAM (da Dynamic RAM), introdotta da Intel nel 1971, è di gran lunga la più diffusa per la realizzazione delle memorie centrali dei computer, ed è realizzata esclusivamente in tecnologia MOS. Sfrutta come elemento di memoria la capacità della porta di un transistore MOS, e dato che la resistenza tra porta e canale è assai elevata, la carica si mantiene per parecchi millisecondi. Per garantire la memorizzazione dei dati durante il funzionamento è perciò necessario ripristinare la carica a intervalli regolari (ciclo di refresh), di solito ogni 2 - 4 millisecondi. Grazie alla semplicità della cella elementare di memorizzazione, costituita da un solo transistore MOS, un chip DRAM permette elevatissime capacità di memorizzazione (fino a 4 Megabit), assai maggiori di quelle delle SRAM. Una seconda caratteristica che differenzia la DRAM dalle altre memorie a semiconduttore è che le linee di indirizzo sono multiplexate per ridurre il numero dei piedini del chip. Ciò comporta che la temporizzazione di una DRAM sia molto più complessa di quella di una SRAM, sia per la tecnica di indirizzamento sia per la necessità dei cicli di rinfresco. Le memorie DRAM sono in genere organizzate con parole da 4 od 8 bit. Lo schema seuente mostra come venga implementata in pratica una memoria DRAM da 4 Megabit, con parole da 8 bit. Memoria RAM statica (SRAM). La memoria RAM statica o SRAM (da Static RAM) è costituita da celle realizzate a flip-flop. Ciascuno di essi è costituito da 6 transistori MOS, e mantiene l’informazione fin tanto che il chip è alimentato, senza bisogno di un circuito di rinfresco. Rispetto alla memoria DRAM ha un tempo di accesso più breve (10 ns contro 60) e anche un tempo di ciclo più breve (da una decina di ns se in tecnologia ECL a un centinaio di ns se in tecnologia c-MOS), in quanto non richiede una pausa tra accessi successivi. È anche più costosa da produrre, per cui il suo uso è limitato alle memorie cache. Una memoria SRAM è costituita da una matrice di celle, pari al numero di bit, e da circuiti di selezione e controllo, come mostra lo schema a lato. Memoria RAM non volatile (NOVRAM). Un tipo particolare di memoria di lettura/scrittura è costituito dalla memoria RAM non volatile o NOVRAM (da Not Volatile RAM), che mantiene il contenuto anche in assenza di alimentazione elettrica. Una NOVRAM è costituita da una memoria SRAM collegata a una memoria di sola lettura cancellabile e programmabile (EPROM). Allo spegnimento del sistema la sezione RAM scarica il suo contenuto nella EPROM, che a sua volta lo riversa nella RAM alla riaccensione. La EPROM fa parte di una numerosa categoria di memorie elettroniche permanenti, che possono essere scritte dall’utente mediante apparecchiature specifiche chiamate programmatori. Vediamo le principali. • PROM (da Programmable ROM). Sono programmabili una sola volta e impiegano una tecnologia a micro-fusibili, che possono essere bruciati in modo irreversibile mediante l’applicazione di opportuni segnali. Lo stato di ogni microfusibile è associato a un singolo bit della PROM. •EPROM (da Erasable PROM). Sono programmabili e cancellabili mediante esposizione alla luce ultravioletta; si basano sull’iniezione di una carica elettrica sulla porta isolata di un transistore MOS che ha la funzione di memorizzare lo stato del bit a esso associato. Il mantenimento della carica è garantito per tempi dell’ordine di alcune decine di anni (in opportune condizioni operative). Possono essere integralmente cancellate mediante l’esposizione a radiazione ultravioletta di una particolare lunghezza d’onda; a tale fine vengono alloggiate in un contenitore ceramico con una finestrella di quarzo trasparente, attraverso il quale il chip interno viene esposto alla luce. •EAROM (da Electrically Alterable ROM) o EEPROM (da Electrically Erasable PROM). Sono programmabili e cancellabili mediante opportuni segnali elettrici. Vengono utilizzate di solito per mantenere dati, programmi o parametri di configurazione modificabili dall’utente durante il funzionamento del sistema. Normalmente consentono di cancellare e riprogrammare dati a livello di singolo byte. Consentono 10-100mila cicli di cancellazione/scrittura. •memorie flash. Sono simili alle EEPROM, ma vanno cancellate a blocchi (e non un byte alla volta). Per tale ragione sono usate per integrare o rimpiazzare i dischi rigidi nei computer portatili, o come dotazione originaria o come scheda aggiuntiva da inserire in uno slot di tipo PCMCIA. Consentono oltre 100mila cicli di cancellazione/scrittura. Unità centrale di elaborazione La CPU può essere realizzata da più schede contenenti circuiti integrati e connessioni elettriche (come nei grandi mainframe), oppure da un singolo circuito integrato detto microprocessore (come nei personal computer). Dal punto di vista funzionale essa è costituita da: • una unità di controllo • una unità di calcolo • vari registri • una memoria interna. I registri. Il principale elemento circuitale di una CPU è detto registro. Esso è un circuito digitale in grado di memorizzare temporaneamente una parola costituita da un certo numero di bit, detto capacità del registro, analogamente a quanto accade in una locazione di memoria. I registri più diffusi hanno capacità di 16 bit, ma vi sono anche componenti in grado di memorizzare da 4 a 64 bit; alcuni registri inoltre hanno una capacità variabile (in genere da 1 a 64 bit) che può essere selezionata in funzione delle esigenze di progetto. La maggior parte dei registri usa come elementi di memorizzazione dei circuiti detti flip-flop (gli stessi impiegati nelle celle di memoria delle RAM statiche). Un registro contiene in genere un dato prelevato dalla memoria per essere elaborato dalla CPU ma, a differenza di una locazione di memoria, esso è di solito usato per manipolare un dato, oltre che per memorizzarlo. Ad esempio, la parola binaria contenuta in un registro può subire le seguenti manipolazioni: • scorrimento di una posizione di bit a destra o a sinistra, corrispondenti rispettivamente alla divisione o moltiplicazione per la base del numero caricato nel registro; • incremento o decremento di 1; • cancellazione o reset del contenuto. I trasferimenti e le manipolazioni di dati su un registro sono determinati da singole istruzioni, ciascuna delle quali indica un’operazione da eseguire. Ad esempio, vi sono istruzioni che fanno • caricare un registro da una locazione di memoria; • trasferire la parola contenuta in un registro a una locazione di memoria; • scorrere, incrementare, decrementare o cancellare il contenuto di un registro. Dal punto di vista funzionale, i registri si possono dividere in • registri speciali se hanno funzioni particolari e contengono informazioni specifiche, e • registri di uso generale se possono contenere dati o indirizzi. Alcuni registri sono accessibili direttamente al programmatore, altri sono usati dalla CPU per proprie operazioni interne. I principali registri speciali sono il contatore di programma, il registro indirizzi di memoria, il registro istruzioni. Il contatore di programma o PC (da program counter), detto anche contatore di istruzioni, memorizza una parola binaria usata come indirizzo della locazione di memoria in cui è contenuta la prossima istruzione da eseguire (si dice anche che esso “punta” a quella locazione di memoria). Si tenga presente che le istruzioni di un programma sono memorizzate in locazioni di memoria consecutive. Per esempio, se la prima istruzione di un programma è contenuta nella locazione di memoria 15, il PC è caricato con l’indirizzo 15; questo è inviato alla memoria attraverso il bus indirizzi, causando il prelievo o caricamento, la decodifica e l’esecuzione dell’istruzione contenuta nella locazione 15. Dopo l’esecuzione il PC è incrementato di 1 tramite il registro incremento/decremento indirizzi, in modo da puntare al successivo indirizzo 16. Fanno eccezione le istruzioni di salto e di richiamo di sottoprogrammi. Il PC può anche essere azzerato; in tal caso la prima istruzione del programma può essere caricata nella locazione 0. Il registro indirizzi di memoria o MAR (da Memory Address Register), detto anche buffer indirizzi, memorizza l’indirizzo cui si deve accedere, e che contiene: • un’istruzione o un dato, se si riferisce alla memoria RAM o ROM, oppure • un dato, se si riferisce a una porta di ingresso/uscita. Quando si deve accedere a un’istruzione, il MAR riceve l’ingresso dal PC (vedi figura). Quando si deve accedere a un dato, il MAR è caricato con la parola binaria che punta alla locazione di quella parola in RAM; questo indirizzo fa parte dell’istruzione. Si noti che un contatore di programma e un buffer indirizzi a 20 bit applicano alla RAM o alla ROM un indirizzo in grado di accedere a 220 = 1.048.576 byte di RAM e/o di ROM. Il registro istruzioni o IR (da Instruction Register) è usato per memorizzare temporaneamente la parola istruzione che la CPU preleva dalla locazione di memoria indirizzata dal contatore di programma e che gli arriva attraverso il bus dati. L’istruzione è una parola binaria - detta anche codice operativo - che specifica una determinata operazione e viene decodificata dalla unità di controllo per stabilire quale funzione vada eseguita. La capacità del registro è uguale al numero di bit che compongono un’istruzione. Dato che contiene l’informazione relativa all’operazione in corso di esecuzione, l’IR è detto anche registro dell’istruzione corrente. Le istruzioni elementari che un microprocessore può eseguire costituiscono il suo repertorio di istruzioni (in ingl.: instruction set), e si possono raggruppare nei seguenti gruppi principali: 1. dati, quali move, input, output, load, e store 2. aritmetiche (su numeri interi), quali add e subtract 3. logiche, quali and, or e not 4. controllo di flusso, quali goto, if ... goto, call, e return L’unità di controllo è quella parte della CPU che ne dirige le operazioni. Essa consiste in circuiti che controllano il flusso di informazioni attraverso il processore e coordinano le attività delle altre unità al suo interno. Opera inviando segnali di temporizzazione e controllo alle altre parti del computer, e può essere considerata una macchina a stati finiti. Attualmente l’unità di controllo è implementata come un microprogramma memorizzato in una apposita memoria (generalmente una ROM oppure una PLA). Un microsequenziatore seleziona le parole del microprogramma, i cui bit controllano direttamente le diverse sezioni del computer, quali i registri, la ALU, i bus e le interfacce di ingresso/uscita. Le funzioni svolte dalla unità di controllo variano ampiamente in base all’architettura della CPU, ma di solito comprendono le attività di: • prelievo • decodifica • esecuzione e • memorizzazione dei risultati delle istruzioni presenti in memoria. Tali operazioni costituiscono il cosiddetto ciclo macchina. Nei processori più avanzati, quali i RISC (Reduced Instruction-Set Computer) l’unità di controllo svolge numerose altre funzioni, per cui viene di solito suddivisa in più unità specializzate. Per la scansione sequenziale delle operazioni svolte da una CPU è necessario un segnale di temporizzazione o di clock. Nei primi microprocessori tale segnale era generato da un circuito esterno opportunamente completato da una rete oscillante, o meglio con un oscillatore al quarzo che determinava la frequenza operativa. I microprocessori più recenti invece contengono al loro interno un circuito per la generazione dei segnali di clock e richiedono la sola connessione di una rete esterna o di un cristallo al quarzo. Il periodo dei segnali è attualmente inferiore a 10 nanosecondi (miliardesimi di secondo), che corrisponde a frequenze superiori a 100 MegaHertz (milioni di Hertz). Lo schema di una CPU elementare è riportato in figura. L’unità di calcolo o unità aritmetico-logica (ALU, da Arithmetic Logic Unit) è costituita da alcuni registri e da un circuito logico digitale che esegue le varie operazioni aritmetiche e logiche comandate dalla sezione di controllo. Il principale registro di una ALU è l’accumulatore, la cui capacità è uguale a quella di una locazione di memoria: un microprocessore a 32 bit ha un accumulatore a 32 bit. L’accumulatore può essere caricato dalla memoria e il suo contenuto può essere memorizzato in qualsiasi locazione di memoria; in alcuni microprocessori anche le operazioni di ingresso/uscita con le unità periferiche avvengono attraverso l’accumulatore. L’ALU può elaborare due ingressi, provenienti uno dall’accumulatore e uno dalla memoria o da un altro registro. Con riferimento alla figura, si supponga di volere sommare due numeri binari. A tale fine: • si carica uno di essi (l’augendo) nell’accumulatore tramite un’istruzione CARICA L’ACCUMULATORE, che preleva il numero da una locazione di memoria, quindi • si esegue un’istruzione ADD che preleva un’altra parola (l’addendo) dalla memoria, la pone in un registro temporaneo e la somma al contenuto dell’accumulatore. La somma è memorizzata ancora nell’accumulatore, dove sostituisce l’augendo preesistente (si può determinare anche una diversa destinazione per il dato in uscita dalla ALU). Questa procedura è la stessa per qualsiasi operazione aritmetica o logica: ad esempio in una sottrazione si carica il minuendo nell’accumulatore, il sottraendo nel registro temporaneo e quindi lo si sottrae. Eseguita l’operazione, la differenza si trova nell’accumulatore, dove sostituisce il minuendo. In realtà, l’uscita dell’accumulatore alimenta il latch dell’accumulatore, che è un altro registro che conserva il contenuto dell’accumulatore e fornisce alla ALU uno dei due ingressi (l’altro provenendo dal registro temporaneo). In un’altra architettura molto diffusa, la cosiddetta registroregistro, si possono indicare le provenienze di entrambi gli operandi e il registro di destinazione. Naturalmente, questo approccio richiede una espansione del repertorio di istruzioni del microprocessore, in modo da contenere anche i campi della provenienza e della destinazione degli operandi. In ogni caso, il funzionamento della ALU viene determinato da un segnale inviato dalla unità di controllo, mentre il risultato in uscita comprende anche informazioni aggiuntive inviate a uno speciale registro detto registro di stato. Il registro di stato è un altro registro della ALU, costituito da 8 bit ciascuno dei quali è detto flag e solo alcuni dei quali sono utilizzati. I valori dei flag indicano il verificarsi di determinate situazioni conseguenti all’esecuzione di un’operazione aritmetica da parte della ALU. Infatti quando questa esegue un’operazione aritmetica si producono due dati: • il risultato vero e proprio (inviato all’accumulatore), e • un vettore binario (inviato al registro di stato) le cui componenti danno una serie di informazioni sul tipo di risultato ottenuto. I bit contenuti più di frequente nel registro di stato hanno i nomi e i significati indicati in tabella. La parola binaria contenuta nel registro di stato è detta anche parola di stato del processore o PSW (da processor status word). Osserviamo che nelle figure precedenti abbiamo indicato un solo accumulatore; tuttavia le CPU più recenti hanno 4, 8 o anche 16 accumulatori, detti di solito registri di uso generale, ciascuno dei quali può usare la ALU e fungere da locazione di memoria temporanea per i dati e i risultati intermedi dei calcoli. Tali registri multipli semplificano e rendono più veloce l’esecuzione di una data operazione da parte di un programma. Il fatto che più accumulatori condividano una stessa ALU permette maggiore flessibilità e velocità nel manipolare i dati e nel selezionare le loro sorgenti e destinazioni rispetto a un solo accumulatore. Memoria cache. I microprocessori più recenti sono dotati di una piccola memoria, detta cache, che conserva le istruzioni e i dati usati più spesso oppure più di recente, in modo da rendere più veloce l’accesso alle informazioni richieste. Quando le istruzioni o i dati richiesti dal microprocessore sono presenti nella cache, il tempo necessario per richiamarli è di gran lunga inferiore a quello che sarebbe necessario se quelli stessi fossero presenti nella memoria principale. Se viene usata in modo opportuno, la cache determina un netto miglioramento delle prestazioni, riducendo il tempo di esecuzione di un’istruzione. Naturalmente, al crescere della quantità di cache installata nel sistema, aumentano le probabilità che il processore vi trovi le informazioni necessarie. Secondo indagini recenti, è risultato che nel 95% dei casi le istruzioni e i dati richiesti da un programma si trovano nella cache. La presenza della cache può non avere effetti di rilievo nel caso di programmi molto piccoli o progettati in modo disordinato, ma se viene usata in modo intelligente si ottiene un miglioramento delle prestazioni. Per ottimizzare le prestazioni della memoria cache non vi sono regole precise, e l’utente in genere non ha modo di modificarne l’utilizzo. Il tipo di cache più semplice è quella diretta, che conserva in un solo blocco i dati delle aree più usate della memoria centrale. Un tipo più sofisticato è la cache associativa, in grado di conservare 2, 4 o anche 8 blocchi di dati prelevati da altrettante aree di memoria principale usate più di frequente. Una cache può essere poi unificata se contiene istruzioni e dati, oppure divisa se costituita da due porzioni separate, una per le istruzioni e l’altra per i dati. La seconda soluzione è maggiormente adottata nei sistemi più recenti. In anni recenti è stata inserita nella scheda madre una seconda cache, più grande e più lenta, detta cache di secondo livello Pipeline Oltre alla memoria cache, un altro accorgimento che si usa per rendere più veloce il funzionamento di un microprocessore è la pipeline (letteralmente: tubazione). Mentre le prime CPU elaboravano le successive istruzioni del programma in modo sequenziale attraverso le fasi di prelievo, decodifica ed esecuzione, quelle successive, dotate di pipeline, eseguono simultaneamente più istruzioni, ciascuna a uno stadio diverso nella sua sequenza di elaborazione, con un aumento del numero di istruzioni elaborate per secondo. In particolare la tecnica consente, a parte i primi e gli ultimi cicli, di eseguire in un ciclo tante istruzioni quante sono le fasi in cui è stata frazionata l’esecuzione di una istruzione. Pertanto si può aumentare tale numero di fasi – detto profondità della pipeline – realizzando le cosiddette pipeline estese. In figura è mostrato lo schema di una pipeline a 5 stadi. Naturalmente l’approccio a pipeline può dare luogo a situazioni critiche quando s’incontrano istruzioni di salto. Per risolvere queste ultime si adottano varie strategie, quali i salti ritardati, la previsione dei salti e l’esecuzione di altre istruzioni durante i tempi dei salti ritardati. Stack. Lo stack (pila, catasta) è una struttura realizzata per la memorizzazione temporanea di indirizzi e dati contenuti in alcuni registri del microprocessore - tipicamente contatore di programma, registro istruzioni e accumulatore - se la normale sequenza di esecuzione di un programma viene interrotta, in genere per eseguire un sottoprogramma o per gestire una interruzione. Può essere realizzato tramite particolari registri dedicati (stack hardware) oppure all’interno della memoria RAM (stack software). Lo stack hardware ha il vantaggio di essere molto veloce, ma una capacità limitata dal numero di registri impiegati, e quando si è riempito deve essere copiato in una zona di memoria. Lo stack software, sebbene possa essere definito come una zona qualsiasi di RAM, è localizzato di solito nella parte identificata dagli indirizzi alti di memoria: ad esempio in un microprocessore con 1 Megabyte di RAM, lo stack inizia all'indirizzo 1.048.576; la sua ampiezza è variabile e dipende da come esso viene utilizzato: raramente supera alcune centinaia di byte. Puntatore di stack. L’indirizzo della prima locazione libera dello stack, detta cima dello stack, è contenuto in un registro detto puntatore di stack o SP (da stack pointer). Il suo contenuto, analogamente al contatore di programma, punta a una locazione di RAM; pertanto esso deve essere in grado di indirizzare qualsiasi locazione di RAM, ed è quindi un registro a 20 bit (vedi figura). Il contenuto di un registro è memorizzato nello stack tramite l’istruzione PUSH e prelevato tramite l’istruzione POP. Poiché ogni dato occupa una locazione di memoria, quando una parola è inserita (push) nello stack il puntatore di stack è decrementato di 1, cosicché i successivi dati provenienti dai registri sono memorizzati in locazioni di indirizzi progressivamente decrescenti. Ad esempio, se un’istruzione PUSH memorizza una parola nella locazione 1.048.575, il puntatore di stack è decrementato a 1.048.574, cosicché la successiva istruzione PUSH memorizzerà un nuovo dato nella locazione con questo indirizzo. Pertanto il puntatore di stack punta sempre alla locazione di indirizzo immediatamente inferiore a quello dell’ultima parola memorizzata nello stack. Quando un dato è estratto (POP o PULL) dallo stack, il puntatore di stack è incrementato di 1, cosicché i dati vengono richiamati in ordine inverso a quello con cui sono stati memorizzati, cioè iniziando dall’ultimo memorizzato. Per questa ragione lo stack ha un’organizzazione di tipo “ultimo entrato - primo uscito”, detta anche LIFO (da last in - first out). Nelle CPU che operano in multiprogrammazione l’uso del puntatore di stack è di fondamentale importanza: in tal caso è utile avere a disposizione più puntatori di stack, che consentono di gestire separatamente più aree di memoria come pile distinte. Si possono avere, per esempio, tre puntatori di stack usati dal sistema operativo, e uno usato dai programmi utente. Bus del microprocessore La CPU è collegata alla memoria e alle interfacce per le unità periferiche tramite circuiti di collegamento detti bus interni. Questi sono costituiti da un certo numero di linee parallele (di solito 8, 16 o 32) ciascuna delle quali offre un percorso fisico per ogni bit del dato da trasmettere. In tal modo tutti i bit di una parola binaria sono trasferiti simultaneamente dalla sorgente alla destinazione (trasmissione parallela). I microprocessori hanno di solito tre bus interni: un bus dati, un bus indirizzi e un bus di controllo. Esiste poi un bus esterno, detto bus di espansione, che consente di aggiungere dispositivi hardware a un personal computer usando connettori standard. Bus dati. Il bus dati fornisce il percorso fisico per tutti i trasferimenti di dati tra registri della CPU, memoria RAM/ROM e sezione di ingresso/uscita; questi trasferimenti avvengono in tempi di pochi nanosecondi. In particolare, sul bus dati transitano: • le istruzioni prelevate dalla memoria e dirette al registro istruzioni; • i dati che provengono dalla memoria o da un dispositivo periferico tramite la sezione di ingresso/uscita e sono diretti agli accumulatori o ad altri registri; • i dati trasferiti da un accumulatore alla RAM in un’operazione di memorizzazione, oppure a un dispositivo periferico quale un tubo a raggi catodici. Dato che consente il passaggio dei dati in entrambe le direzioni, il bus dati è di tipo bidirezionale. Per evitare conflitti di livelli logici sulle linee il bus deve essere collegato a una sola sorgente di dati per volta, ma può essere collegato a una o più destinazioni contemporaneamente. Per abilitare selettivamente le varie sorgenti connesse al bus si usano circuiti detti multiplatori di bus e/o piloti di linea a tre stati. Questi ultimi sono componenti paragonabili a interruttori, che permettono di collegare o no una linea logica a un’altra, a seconda dello stato di una linea di controllo. Bus indirizzi. Per comunicare con il mondo esterno un microprocessore deve avere capacità di indirizzamento, in modo da selezionare solo il dispositivo con il quale intende comunicare in un dato istante. A tal fine è usato il bus indirizzi, che permette i trasferimenti nel solo verso CPU circuiti esterni. Per tale ragione esso è di tipo unidirezionale. Normalmente il bus indirizzi ha una larghezza maggiore del bus dati, a esempio 32 bit, potendo così indirizzare 232 = 4.294.967.296 ($ Giga) locazioni o indirizzi diversi. Bus di controllo. La semplice selezione di un dispositivo non è sufficiente per stabilire se l’operazione richiesta sia di lettura o di scrittura: per completare le informazioni scambiate con il mondo esterno il microprocessore dispone perciò di altre linee, dette bus di controllo, pilotate direttamente dall’unità di controllo. I segnali che esso trasporta determinano in ogni ciclo macchina il tipo di operazione che la CPU svolge. Nel caso più semplice è presente una sola linea di lettura/scrittura (read/write, o RW), il cui stato logico definisce l’operazione da eseguire: lettura (R/W=0) o scrittura (R/W=1). In altri casi è presente una seconda linea ingresso/uscita/memoria (input/output/memory, o IO/M), che indica se l’operazione è relativa a porte di ingresso/uscita (IO/M=1) o alla memoria (IO/M=0). In altri casi l’operazione è indicata tramite quattro linee, che possono essere: • IO/R • IO/W • MEMR • MEMW (I/O read) per lettura da ingresso/uscita, (I/O write) per scrittura da ingresso/uscita, (Memory read) per lettura da memoria, (Memory write) per scrittura da memoria. Le quattro linee possono essere anche I/O, MEM, IN, OUT e la loro selezione, a coppie, consente di ottenere le stesse funzioni. Bus di espansione. Il bus di espansione o di ingresso/uscita, nel quale s’inseriscono le schede di espansione, è una estensione della CPU, in quanto aggiungendo su esso delle schede si estendono le capacità della CPU stessa. La rilevanza di questo rispetto al BIOS è che le schede più vecchie sono meno in grado di fare fronte ai moderni bus che operano a velocità più elevate rispetto a quelle originarie di 8 MegaHertz o valori di poco superiori. Inoltre, quando si accede al bus, l’intero computer rallenta fino alla velocità del bus, cosicché è spesso opportuno alterare la velocità del bus o gli stati di attesa tra esso e la CPU per rendere più veloci le operazioni. I principali bus di espansione utilizzati dai personal computer sono stati, in ordine cronologico, • ISA (da Industry Standard Architecture), introdotto nel 1984 con il primo pc IBM; oramai sorpassato. • MCA (da Micro Channel Architecture), standard proprietario IBM del 1987, incompatibile con gli altri; • EISA (da Extended Industry Standard Architecture), evoluzione di ISA, del 1988; anch’esso sorpassato; • VLB (da VESA Local Bus), introdotto nel 1992; oramai sorpassato; • PCI (da Peripheral Component Interconnect), introdotto dalla Intel a metà del 1993; • USB (da Universal Serial Bus) introdotto nel gennaio 1996; • HyperTransport, introdotto nell’aprile 2001; • CSI (da Common System Interface) annunciato dalla Intel per il 2008.