STRUTTURA DEI CALCOLATORI 1 Strutture di interconnessione 1.1 Struttura a singolo bus 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 Passaggio di controllo del bus Struttura interna del bus Lettura e scrittura in memoria ed unità periferiche Memory mapped I/O Evoluzione dei bus Tipi di bus 2 Struttura dei processori 2.1 Il ciclo di istruzione 2.1.1 2.1.2 2.1.3 2.1.4 Diagramma di stato dell’interpretazione di una istruzione Struttura generale dei processori Fase fetch Fasi execute 2.2 Temporizzazione 2.3 Unità di controllo “cablata” 2.3.1 Il clock, il contatore tempi e la rete combinatoria 2.3.2 Funzioni booleane della rete combinatoria della fase fetch 2.4 Unità di controllo microprogrammata 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 La temporizzazione nelle unità di controllo microprogrammate Il formato di microistruzione Decodifica del codice operativo Diagramma a blocchi dell’unità di controllo microprogrammata Unità aritmetica e logica 1 Strutture di interconnessione La struttura del modello di von Neumann si compone di a) un processore b) una memoria c) un canale di comunicazione (bus) Per comunicare con il mondo esterno, il modello di von Neumann deve essere dotato di un ulteriore canale di comunicazione: il bus di input/output Struttura con canale di comunicazione diretto memoria – unità periferiche (Direct Memory Access) 1.1 Struttura a singolo bus Una soluzione più elastica consiste nel collegare tutti i componenti, per esempio i processori, le memorie e le unità di I/O, ad uno switch centrale, che regola ed arbitra tutte le comunicazioni. Una struttura molto più semplice, che conserva le caratteristiche di generalità e flessibilità dello switch centrale, con la limitazione di permettere soltanto una comunicazione alla volta, è la struttura a singolo bus. Il bus è condiviso fra tutte le unità del sistema. La comunicazione può avvenire fra due qualsiasi unità, non soltanto con il processore. Inoltre, una sola unità alla volta può trasmettere, mentre più di una unità possono ricevere. Il bus deve essere dotato di un insieme di linee di controllo sufficientemente generale, che Struttura a singolo bus tenga conto della diversa natura delle unità componenti il sistema. L’unità che detiene il controllo del bus viene denominata master, tutte le altre slave. 1.1.1 Passaggio di controllo del bus I segnali per il passaggio del controllo del bus sono, come la maggior parte dei segnali di controllo, in logica negativa, cioè allo “0” logico è associato il livello di tensione più alto (es. 5 volt) ed all’”1” logico il livello di tensione più basso (es. 0 volt). La richiesta del bus, Bus Request, è inviata dall’aspirante master portando questo segnale da livello alto a livello basso. Il processore risponde, dopo aver portato in alta impedenza le sue linee di bus in uscita, asserendo (cioè ponendo a livello basso) la linea di concessione del bus, Bus Grant. Quando l’unità riceve questo segnale può diventare master e, contemporaneamente, invia un segnale di riconoscimento, Bus Grant Acknowledgement, che gli è stato accordato il bus. Al completamento della sua operazione, riporterà a livello alto (cioè negherà) il segnale di riconoscimento. Tale passaggio, da basso ad alto del segnale di Segnali di sincronizzazione richiesti per il riconoscimento, viene utilizzato dal passaggio del controllo del bus dal processore processore come segnale che può ad un’altra unità del sistema. riprendere il controllo del bus. Nel caso più generale, più unità possono essere nella condizione di voler ottenere il controllo del bus. Le linee di controllo non possono più essere dirette ma debbono essere comuni a tutte le unità. Inoltre, in caso di richieste simultanee, è necessario un meccanismo di arbitraggio che risolva il conflitto. La figura mostra una semplice evoluzione del caso precedentemente presentato, con le linee Bus Request e Bus Grant Acknowledgement in comune fra tutte le unità, mentre la linea Bus Grant è utilizzata con modalità daisy-chain. Anche questa è da considerare una linea comune, ma essa passa attraverso le varie unità per risolvere i conflitti secondo una priorità determinata dalla posizione fisica delle stesse sulla linea di Bus Grant rispetto al processore . Se un’unità riceve un segnale di Bus Grant, ed ha fatto una Bus Request, essa la utilizza per prendere il controllo del bus, altrimenti si limita a propagare il segnale di Bus Grant. I meccanismi di arbitraggio possono essere abbastanza più complessi per tener conto, ad es., di priorità non fisse. Inoltre essi possono essere centralizzati, cioè incorporati nel processore o demandati ad una apposita unità esterna, oppure distribuiti fra le varie unità componenti il sistema. 1.1.2 Struttura interna del bus Il Bus di indirizzi è usato per selezionare l’unità con la quale deve essere stabilita la comunicazione. E’ unidirezionale, è prodotto in uscita dall’unità di calcolo degli indirizzi interna al master, e va in input alle unità slave per poterle selezionare. La larghezza del Bus di indirizzi fissa la dimensione dello Componenti di un bus spazio di indirizzi, cioè il numero delle celle di memoria e dei registri delle unità di I/O selezionabili. Il Bus di dati è bidirezionale. Le Linee di controllo in input al master si riferiscono a segnali con cui le altre unità del sistema gli comunicano il verificarsi di particolari condizioni o eventi, sui quali deve essere sincronizzata l’elaborazione futura. Le Linee di controllo in output corrispondono a segnali o comandi che il master invia alle altre unità per evocarne l’operazione. Associata ad ogni unità slave esiste una decodifica degli indirizzi. Vettore di n bit 2n uscite tutte uguali a “0” logico eccetto quella la cui posizione corrisponde al valore del dato in ingresso 1.1.3 Lettura e scrittura su una unità di I/O o in memoria Per poter leggere o scrivere un dato su una unità di I/O o in memoria, molti processori usano i segnali Read e Write, accompagnati da altri due segnali: Memory Request, se l’operazione è in memoria centrale, Input Output Request se invece è con unità periferica. Linee di bus per la lettura e scrittura in memoria e nelle unità periferiche Il segnale di richiesta di memoria, Memory Request, viene usato per selezionare la memoria in blocco, ma la memoria è di solito implementata come un insieme di moduli o banchi. Il segnale viene usato per abilitare un decodificatore (input di Enable). A questo decodificatore vengono inoltre mandati i bit di ordine alto del bus di indirizzi, per selezionare uno dei banchi di memoria. Gli altri bit dell’indirizzo vengono inviati a tutti i banchi. Le uscite del decodificatore vanno singolarmente agli input Chip Select di selezione dei moduli di memoria, in modo da selezionare uno ed uno solo di questi. Le linee di indirizzo inviate ad ogni modulo di memoria verranno decodificate, a loro volta, Se ci sono più banchi di memoria dalla logica di decodifica che fa parte di ogni modulo. 1.1.4 Memory mapped I/O Le unità di I/O e la memoria possono suddividersi lo spazio di indirizzi fissato dal bus di indirizzi. In tal caso, non c’è più bisogno di ulteriori linee, come Memory Request e Input Output Request, perché è l’indirizzo stesso che viene utilizzato per distinguere se si tratta di un’operazione di I/O o di memoria. Memory mapped I/O. Lo spazio di indirizzi è stato suddiviso in due 2 parti uguali: la parte superiore (An-1 = 1) è assegnata alle unità periferiche, mentre la metà inferiore (An-1 = 0) alla memoria centrale Memory mapped I/O con spazio di indirizzi suddiviso in 16 parti. Di queste, si può decidere di assegnarne un certo numero alla memoria e le parti restanti all’I/O. 1.1.5 Evoluzione dei bus I primi PC usavano la soluzione più semplice. Un solo insieme di fili percorreva l’intera mainboard. La CPU, la memoria e tutti gli altri dispositivi di I/O erano connessi a questi fili, cioè al singolo bus. I moderni computer combinano tutte le funzioni di tutti I devices in due chip. Il chip Northbridge connette alla CPU la memoria (front side bus (FSB) e il video AGP. Il Northbridge è quindi connesso ad un chip Southbridge che supporta la keyboard, il mouse, il floppy, l’hard disk, il CD, la LAN, l’USB, il FireWire e il PCI. Questi due chip stanno nel mezzo di quella che può essere considerata una configurazione a “stella” o ad “hub”. I devices si connettono o al North o al Southbridge ed i chip forniscono la funzione di interconnessione o switching. Quando tutti i devices erano connessi ad un singolo insieme di fili (singolo bus), c’era soltanto una velocità di clock che si applicava alla CPU, alla memoria ed a tutti I devices di I/O. Ora, invece, poichè ciascun bus è separato, ciascuno può avere il suo proprio clock. La stessa velocità Bus di I/O Bus multipli FireWare Un tipico sistema Pentium II SCSI (Small Computer System Interface) era molto diffusa in passato in ogni tipologia di computer, mentre attualmente trova un vasto impiego solamente in workstation, server e periferiche di fascia alta (cioè con elevate prestazioni). I computer desktop e portatili sono invece di solito equipaggiati con l' interfaccia ATA/IDE (Advanced Technology Attachment e Integrated Drive Electronics), rinominato PATA per distinguerlo da SATA (Serial Advanced Technology Attachment), per gli hard disk, e con l' interfaccia USB (Universal Serial Bus) per altre periferiche di uso comune. Queste ultime interfacce sono più lente della SCSI, ma anche più economiche. Notare che l' USB utilizza lo stesso set di comandi dello SCSI per implementare alcune delle sue funzionalità. PCI (Peripheral Component Interconnect) è l' interfaccia sviluppata da Intel intorno agli anni Novanta per collegare al computer le più svariate periferiche. La larghezza di banda dell' interfaccia PCI è rimasta negli anni ancorata a 133 MBytes/s, generata da una trasmissione dati con frequenza pari a 33MHz a 32bit. Sebbene l' interfaccia PCI abbia fatto segnare un notevole passo avanti nell' evoluzione dei pc, sia per il costo contenuto sia per le buone (e inizialmente sufficienti) prestazioni che ne hanno decretato la diffusione di massa rimpiazzando ISA (Industry Standard Architecture) (o Bus AT), i primi limiti si sono fatti sentire poco dopo in sistemi come server e workstation, dove vi è bisogno di un enorme larghezza di banda per la trasmissione dei dati. Fu così che si iniziò a cercare e progettare sostituti per questa interfaccia: i più fortunati sono stati il PCI a 66MHz, il PCI X (a 3.3v)ed ora il PCI Express. 1.1.6 Tipi di bus Bus Sincrono: Include un clock nelle linee di controllo Un protocollo fisso per la comunicazione che è relativo al clock Vantaggio: richiede pochissima logica e può essere molto veloce Svantaggio: Ogni dispositivo sul bus deve andare alla stessa velocità di clock Bus Asincrono: Non usa un clock Può servire una grande varietà di dispositivi Richiede un protocollo di handshaking Bus Memoria-Processore (specifico del progetto): Corto e ad alta velocità Ha bisogno solo di accordarsi con il sistema di memoria Massimizza la banda memoria-processore Connette direttamente al processore Ottimizzato per trasferimenti di blocchi di cache Bus di I/O (standard industriali): Usualmente è lungo e più lento Ha bisogno di accordarsi con una grande varietà di dispositivi di I/O Connette al bus Memoria-Processore o al bus di Backplane Bus di Backplane (standard o proprietari): Una struttura di interconnessione all’interno del telaio Permette ai processori, ai dispositivi di memoria e di I/O di coesistere. Vantaggio di costo: un bus per tutti i componenti. 2 Struttura dei processori La struttura interna di un processore deve fornire le funzionalità richieste dal livello di architettura di calcolatore, e cioè l’elaborazione dei dati, degli indirizzi e delle istruzioni. Si può considerare il processore come un interprete di istruzioni che, per ogni istruzione, effettui delle sequenze di cambiamenti di stato che portino dallo stato iniziale allo stato finale definiti per quella istruzione. La situazione è analoga a quella dei livelli superiori, dove un programma specifica, tramite le istruzioni che lo compongono, una sequenza di cambiamenti di stato che portano da uno stato iniziale ai risultati finali della risoluzione di un problema. Il problema risolto dal programma dei livelli superiori è ora sostituito dall’istruzione di macchina che verrà “risolta” dal processore. Per ogni istruzione, dovrà essere specificata la sequenza di operazioni elementari che determinano i cambiamenti di stato richiesti sulla struttura fisica del calcolatore. Tali operazioni elementari sono in diretta corrispondenza con le unità fisiche componenti il calcolatore. L’interpretazione di ogni istruzione da parte del processore avviene attraverso un insieme di fasi che compongono quello che viene chiamato il ciclo di istruzione. 2.1 Il ciclo di istruzione Il ciclo di istruzione si compone delle seguenti fasi: 1) 2) 3) 4) 5) 6) 7) 8) estrazione dell’istruzione dalla memoria; calcolo dell’indirizzo della prossima istruzione tramite l’avanzamento del PC; decodifica del codice operativo; calcolo dell’indirizzo dell’eventuale operando; estrazione dell’operando dalla memoria; esecuzione; calcolo dell’indirizzo del risultato; immagazzinamento del risultato in memoria. Alcune di queste fasi corrispondono ad operazioni in memoria, altre ad operazioni del processore. 2.1.1 Diagramma di stato dell’interpretazione di una istruzione Gli stati controllati dal processore sono a sinistra, quelli controllati dalla memoria a destra. Se non vi sono vincoli di sequenzialità, fasi di tipo diverso possono sovrapporsi nel tempo. Alcune delle fasi possono essere assenti in determinate istruzioni, o possono essere eseguite ripetutamente in altre. La sequenza è ripetutamente eseguita per tutte le istruzioni di un programma: essa assume il nome di ciclo di istruzione. Occasionalmente si può ritornare all’interno del ciclo, come accade nella elaborazione di stringhe. All’interno del ciclo di istruzione, si usa fare una suddivisione in fase fetch, comprendente le fasi (1), (2) e (3), che è la stessa per ogni istruzione eseguita, e in fase execute, specifica per ogni tipo d’istruzione. 2.1.2 Struttura generale dei processori Le unità costituenti un generico processore sono: - unità di bus: ha il compito di stabilire la comunicazione con le unità esterne; - unità di istruzione: estrae e decodifica le successive istruzioni del programma in esecuzione. Il risultato della decodifica servirà a selezionare la particolare fase execute corrispondente al codice operativo dell’istruzione estratta; MAR MBR PC IR - unità aritmetica e logica: esegue le operazioni di elaborazione dati specificate durante la fase execute dell’istruzione in corso di interpretazione; - unità di indirizzo: esegue il calcolo dell’indirizzo; - unità di controllo o di governo: riceve gli input dal decodificatore d’istruzione e genera l’insieme di controlli e di temporizzazioni necessarie all’espletamento della corrispondente fase execute. L’unità di controllo ha anche il compito di generare la temporizzazione per la fase fetch e per la gestione delle eccezioni. 2.1.3 Fase fetch Ogni ciclo di istruzione comincia con l’invio, sul bus di indirizzi, dell’indirizzo dell’istruzione da estrarre. Tale indirizzo è contenuto nel PC, MAR che è uno dei registri di indirizzo che fanno parte dell’unità di indirizzi. L’indirizzo impostato dal PC sul bus di MBR indirizzi interno viene “latched” in un registro di indirizzi, spesso denominato MAR (Memory Address Register), posto IR PC nell’unità di bus (MAR := PC). Un’operazione sul bus esterno richiede, infatti, che l’indirizzo sul bus di indirizzi sia impostato per un tempo piuttosto lungo per permettere alle unità esterne, collegate al bus, di decodificare e, quindi, riconoscere l’indirizzo. Solo dopo che è passato questo tempo, l’unità esterna selezionata potrà impostare o prelevare dal bus dati l’informazione. Nel caso in questione, l’informazione è l’istruzione che il processore richiede (RD) ad una unità di memoria. Nel tempo che l’unità di memoria impiega ad inviare l’istruzione al processore, quest’ultimo può fare altre operazioni (parallelismo fra processore e memoria). Tale parallelismo è reso possibile dalla presenza, già menzionata, di un registro buffer quale è il MAR. Una tipica operazione che può essere anticipata è l’avanzamento del PC (PC := PC + 1), in modo che punti alla prossima istruzione, o alla successiva parola dell’attuale istruzione, in dipendenza dal formato d’istruzione. Per lo stesso motivo, alla fine della fase fetch, è presente sul bus di dati o l’intera istruzione o la sua prima parola. In tutti e due i casi il codice operativo è presente sul bus di dati e conviene catturarlo nel registro IR (Instruction Register) dell’unità di istruzione (IR := MBR). In questo modo, si libera il bus di dati interno per ulteriori cicli di bus. Il bus di dati esterno aveva già provveduto a liberarlo l’unità di bus, memorizzando l’informazione ivi presente nel suo registro buffer di dati, generalmente chiamato MBR (Memory Buffer Register). Una volta che il codice operativo è nell’IR, la prossima fase da compiere è quella di decodifica. MAR MBR PC IR 2.1.4 Fasi execute Mentre la fase fetch è condivisa da tutte le istruzioni, esistono tante fasi execute quanti sono i codici operativi. Ognuna di esse rimanda ad un differente interprete. Per ognuna di esse si tratta di stabilire, analogamente alla fase fetch, le operazioni elementari richieste per eseguire la corrispondente interpretazione. Le differenti fasi execute sono selezionate dal processo di decodifica del codice operativo. Sia la fase fetch che le fasi execute debbono specificare i trasferimenti fra registri coinvolti, la serie dei comandi da inviare alle unità interessate e la loro temporizzazione, cioè la loro durata e il tempo di inizio. MAR MBR PC IR 2.2 Temporizzazione Temporizzazione è la sequenza di comandi da inviare alle varie unità che concorrono all’espletamento della fase fetch e delle fasi execute.Una volta individuate le operazioni da compiere per una singola fase, queste vanno tradotte nelle sequenze di comandi o segnali corrispondenti. Per la fase fetch, per es., erano state individuate le seguenti operazioni, alcune da effettuare in sequenza (rappresentate su linee differenti) altre in parallelo (rappresentate sulla stessa linea, separate da un “;”): 0: 1: 2: MAR := PC; RD PC := PC + 1; RD IR := MBR Se si conviene che le operazioni su ogni linea abbiano tutte la stessa durata, si comprende la ragione della ripetizione dell’operazione RD su due linee: si ottiene, così, di far durare l’operazione di lettura il doppio (se necessario, il triplo o il quadruplo, ripetendola su più linee) delle altre operazioni. L’operazione MAR := PC è una tipica operazione di trasferimento fra registri. Essa è realizzata inviando un segnale di abilitazione di durata opportuna all’input Enable del registro di destinazione. Si suppone di usare logica positiva anche per i segnali di controllo PC EN MAR Se i registri sorgente dovessero essere più di uno, si può adoperare a monte del registro di destinazione un selettore a due o più vie, in cui l’input Indirizzo sceglie la direzione di provenienza. Se l’indirizzo per la provenienza dal PC è “0”, la temporizzazione per la fase fetch potrebbe essere quella riportata in figura. E’ bene cercare di avere segnali di durata multipla l’uno dell’altro (come nel caso del segnale di lettura in memoria la cui durata è un multiplo di quella del segnale di abilitazione ai registri). Inoltre, se è possibile, è meglio usare dei livelli (come nel caso dell’indirizzo ai selettori), o riusare dei segnali (come nel caso dell’incremento del PC che utilizza lo stesso segnale di EN (MBR)). La temporizzazione delle fasi execute è realizzata allo stesso modo. MREQ, RD EN (MAR) Indirizzo (S) = 0 EN (MBR) EN (IR) Incrementa (PC) Indirizzo EN S MAR 2.3 Unità di controllo “cablata” Se le istruzioni del livello di macchina sono direttamente interpretate in hardware da circuiti che hanno il compito di generare la temporizzazione corrispondente alla fase fetch ed alla fase execute di ogni istruzione, l’unità di controllo è definita come “cablata”, cioè consistente di reti combinatorie e circuiti sequenziali. Questo approccio è stato universalmente adottato dai calcolatori delle prime generazioni, dalle architetture ad alte prestazioni ed, attualmente, da molte architetture che seguono il cosiddetto modello RISC – Reduced Instruction Set Computer. A queste si contrappongono le architetture CISC – Complex Instruction Set Computer – che, per avere istruzioni e metodi di indirizzamento più complessi, beneficiano, almeno in parte, dei vantaggi della microprogrammazione. La funzione di un’unità di controllo cablata è quella di produrre temporizzazioni come quella vista per la fase fetch. Un metodo per ottenere ciò, è quello di usare gli output degli stadi di un contatore degli impulsi del clock del processore come input ad un circuito combinatorio. 2.3.1 Il clock, il contatore tempi e la rete combinatoria Il clock emette un treno di impulsi a frequenza costante molto elevata. Se questi impulsi entrano nell’input Avanzamento di un contatore, si produrranno alle sue uscite altri treni di impulsi di frequenza metà, un quarto, ecc., corrispondentemente di larghezza doppia, quadrupla, ecc., in ordine crescente di stadi del contatore stesso. Questo è chiaramente illustrato dalla tavola della verità del contatore. La varietà di impulsi così ottenuta è utilizzata dalla rete combinatoria per produrre la successione di comandi relativi alla fase fetch o alla fase execute selezionata dalle linee provenienti dal decodificatore di istruzioni. La rete combinatoria è una rete multifunzionale, cioè ha molte uscite, ognuna corrispondente ad una particolare funzione booleana degli ingressi. 2.3.2 Funzioni booleane della rete combinatoria per la fase fetch In questa figura, sono state ricavate le funzioni booleane relative alla temporizzazione della fase fetch. Si noti l’accorgimento di utilizzare durate di impulsi uguali o multiple di semiperiodi dei treni ad onde quadre in uscita dal contatore tempi. Una volta ottenuta la tavola della verità della rete logica complessiva corispondente all’intera temporizzazione, essa viene realizzata di solito usando dispositivi logici strutturati general purpose, quali i PLA – Programmable Logic Array, o le ROM – Read Only Memory. 2.4 Unità di controllo microprogrammata Al di là del fatto di esprimere sinteticamente ed elegantemente la sequenza di operazioni necessarie all’espletamento della fase fetch, la sequenza: 0: 1: 2: MAR := PC; RD PC := PC + 1; RD IR := MBR ha tutte le caratteristiche di un programma e, se esistesse una macchina in grado di interpretarlo, ecco che l’insieme dei due ci fornirebbe l’unità di controllo per l’architettura di calcolatore. Analogamente alla fase fetch, anche le fasi execute, se scritte come sequenze di istruzioni a livello più basso, potrebbero essere interpretate da tale macchina. Ma una macchina siffatta altro non è se non il modello di von Neumann applicato ad un’altra architettura, sebbene di livello inferiore. Una tale architettura ha lo stesso tipo di unità funzionali dell’architettura di livello superiore, ed infatti ne conserva i nomi, con l’aggiunta del prefisso micro. I microprogrammi che costituiscono un interprete sono ottenuti tramite traduzione da un linguaggio simbolico del tipo su presentato e debbono essere memorizzati in una memoria di controllo o di microprogrammazione. Per non degradare le prestazioni, è necessario che tale memoria sia almeno n volte più veloce della memoria centrale se n è la somma del numero di microistruzioni della fase fetch e del numero medio di microistruzioni delle fasi execute. Infatti, le unità di controllo microprogrammate cominciarono ad essere realizzate solo quando la tecnologia dei circuiti integrati permise di produrre memorie sufficientemente veloci. 2.4.1 La temporizzazione nelle unità di controllo microprogrammate Il problema della temporizzazione di ogni istruzione viene scomposto, con la microprogrammazione, in sottoproblemi di temporizzazione più elementari. Il ciclo stesso di microistruzione, coincidente con il ciclo della memoria di controllo, è un modo semplice e sistematico di introdurre una temporizzazione. In ogni ciclo possono essere eseguite in parallelo diverse microoperazioni o microordini. Se questo semplice meccanismo non si dovesse rivelare sufficiente, si può ricorrere anche a realizzare una temporizzazione interna al ciclo di microistruzione. Questa consiste nel suddividere il ciclo di microistruzione in due o più sottocicli identici e nell’abilitare l’esecuzione di alcuni microordini soltanto nel 1° sottociclo, di altri nel 2° sottociclo, e così via. Se esiste un solo ciclo non suddiviso, si parla di controllo monofase, altrimenti si usa il termine di controllo polifase. Per es., come è noto, l’immagazzinamento del risultato di una operazione della ALU può essere fatto solo dopo aver selezionato gli operandi al suo ingresso. In una organizzazione bifase, la selezione dei due operandi (dal file di registri generali, dal bus interno, ecc.) verrebbe abilitata nel 1° sottociclo, mentre l’immagazzinamento del risultato, con un eventuale shift, verrebbe abilitato nel 2° sottociclo. La microarchitettura ha una visibilità delle risorse hardware maggiore di quella dell’architettura di calcolatore. Per questa ragione, ed anche per poter controllare in parallelo più risorse, il formato di microistruzione è completamente diverso da quello di istruzione. 2.4.2 Il formato di microistruzione A differenza delle istruzioni di macchina, le microistruzioni esibiscono un gran numero di campi, ognuno controllante una diversa unità. Alcuni campi sono relativi a comandi. Per es., i campi RD e WR sono campi lunghi 1 bit che, se posti uguali ad “1”, inviano sulle rispettive linee di controllo un comando di Read o di Write. Altri campi sono dei codici di funzione, come il campo ALU che rappresenta quale operazione è richiesta alla unità aritmetica e logica. Altri campi possono rappresentare degli indirizzi. Per es., un campo può essere il numero di registro, in un file di registri generali, su cui si intende operare. Dato che la lunghezza di microistruzione può essere molto grande, si tende a codificare in un unico campo informazioni espresse in più campi. Per es., se il risultato di un’operazione può essere memorizzato in 8 registri diversi, si possono impiegare 8 campi di 1 bit l’uno, oppure un campo di 3 bit. Col primo metodo si può, in linea di principio, memorizzare il risultato anche in tutti gli 8 registri contemporaneamente, col secondo, invece, si può memorizzarlo solo in uno degli 8. La codifica di un campo è un metodo molto utile anche quando due o più campi risultano avere configurazioni reciprocamente incompatibili. Per es., l’abilitazione di una dato sul bus di dati da tre diverse sorgenti non può essere data, come è stato già detto, contemporaneamente. Un modo molto semplice di risolvere il problema di evitare di incorrere in errori di microprogrammazione in questo caso, è di usare un campo codificato di 2 bit che, con le sue 4 configurazioni distinte, permette di selezionare in modo esclusivo una ed una sola delle tre sorgenti, o nessuna di esse. Una microistruzione con campi decodificati, in cui ogni bit controlla direttamente un input ad una unità di calcolatore, è spesso detta di tipo orizzontale, mentre una con campi codificati è di tipo.verticale. Quest’ultima realizza un notevole risparmio di memoria di controllo, ma a spese di una maggiore lentezza, dovuta alla necessità di decodificare i vari campi. Inoltre, non consente di sfruttare al massimo il parallelismo esistente nell’hardware. Il formato più usuale è quello misto, con alcuni campi codificati ed altri no. Inoltre, esistono vari schemi di codifica, ognuno dei quali tende ad adattarsi meglio a determinate caratteristiche del particolare interprete. Un’altra differenza con le istruzioni in linguaggio di macchina, sta nel fatto che è incluso esplicitamente nella microistruzione l’avanzamento o, alternativamente, l’aggiornamento del MPC (Micro Program Counter). Esiste, cioè una sezione della microistruzione che è destinata al cosiddetto sequenziatore, il cui compito è appunto quello di determinare l’indirizzo della prossima microistruzione da eseguire. Tale campo è formato da 3 sottocampi: un sottocampo code che contiene il codice operativo di un microjump condizionato, un sottocampo cond che rappresenta la condizione su cui effettuare il test, un sottocampo addr che esprime l’indirizzo di memoria di controllo a cui saltare se la condizione è verificata. 2.4.3 Decodifica del codice operativo La decodifica del codice operativo dell’istruzione di macchina rimanda, invece che ad un circuito differente per ogni codice operativo, all’indirizio di inizio di un differente microprogramma. Essa viene comunemente effettuata tramite una memoria di mapping. Il codice operativo viene inviato sulle linee di indirizzo di tale memoria in modo da selezionare una locazione, nella quale si è andato a porre l’indirizzo di micromemoria in cui comincia il microprogramma. Se successivamente si vuole spostare il microprogramma in un’altra area della memoria di controllo, basterà cambiare il contenuto della corrispondente locazione in memoria di mapping con il nuovo indirizzo. 2.4.4 Diagramma a blocchi dell’unità di controllo microprogrammata Una unità di controllo microprogrammata è dotata di un contatore di microprogramma MPC e di un registro di microistruzione MIR. L’unità di controllo riceve l’indirizzo di inizio del microprogramma da eseguire dalla memoria di mapping. L’indirizzo della prossima microistruzione, oltre che essere fornito dalla memoria di mapping, può essere dato dall’avanzamento automatico del MPC, oppure può essere il frutto di un microjump. Quale delle tre alternative viene decisa dal controllore della prossima istruzione in base ai campi codice e cond della microistruzione. Il campo cond seleziona per il test uno dei bit di condizione N, Z, V o C, prodotti dall’unità aritmetica e logica. L’uscita del controllore seleziona infine la sorgente per il prossimo indirizzo da caricare in MPC. La microistruzione, posta alla locazione di memoria puntata da MPC, viene estratta e caricata nel MIR, da cui si dipartono le linee dirette alle altre unità. 2.4.5 Unità aritmetica e logica L’unità aritmetica e logica è formata essenzialmente da un insieme di registri generali, una ALU propriamente detta, ed una unità di shift. I registri generali sono collegati, in genere, ad entrambi gli input della ALU. Per questo sono selezionabili due registri contemporaneamente nella microistruzione, mediante i due campi di indirizzo denominati A e B. Tramite il campo ST di un solo bit, si può decidere di immagazzinare il risultato nel registro selezionato dal campo B. La logica di decodifica degli indirizzi A e B è costruita dentro quella che viene chiamata una RAM a due porte. Il bus di dati interno è collegato ad uno dei due input della ALU, in multiplexing con una delle uscite dei registri generali. I due latch A e B vengono impiegati per presentare dati stabili alla ALU qualora si utilizzino gli stessi registri come input e come output dell’operazione. I campi ALU ed SH della microistruzione specificano, rispettivamente, il tipo di funzione richiesta alla ALU e se si desidera effettuare uno shift sul risultato, ed il tipo di shift. Un risultato collaterale della ALU è dato dai bit di condizione N, Z, V e C, il cui valore può essere interrogato sia dalle istruzioni della architettura di calcolatore che dalle microistruzioni. Queste ultime utilizzano il campo cond per decidere la prossima microistruzione da eseguire.