I livelli di astrazione nella rappresentazione di un calcolatore L’architettura generale di un calcolatore Mariagiovanna Sami 2007-08 1 LA GERARCHIA Applicazione tipica: può consistere di milioni di linee di codice e servirsi di librerie software che realizzano funzioni complesse; Lo hardware esegue solo istruzioni molto semplici di basso livello (le istruzioni di macchina); le istruzioni aritmetiche sono solo istruzioni elementari a due operandi, etc; Passare dall’applicazione a queste istruzioni richiede vari livelli di sw che traducano le operazioni di alto livello in operazioni di macchina. 20072007-08 -2- LA GERARCHIA Fra applicazione (il livello più esterno) e hardware si trovano vari livelli e tipi di software di sistema; classi di sw di sistema presenti per qualsiasi calcolatore: ¾ ¾ 20072007-08 Sistema operativo Compilatore -3- LA GERARCHIA Una vista semplificata dei livelli gerarchici hw/sw: Sw applicativo Sistema operativo Un’applicazione complessa ha in realtà più livelli di sw applicativo 20072007-08 hardware -4- LA GERARCHIA Sistema operativo: interfaccia fra programma di utente e hardware: fornisce funzioni di supervisione e servizi vari, in particolare: 1. 2. 3. 20072007-08 Gestisce le operazioni fondamentali di ingresso e uscita; Alloca memoria di lavoro e memoria di massa; Supporta la condivisione del calcolatore fra più applicazioni che lo usano simultaneamente. -5- LA GERARCHIA Compilatore: traduce il programma sorgente, scritto dal programmatore in un linguaggio ad alto livello, in un programma oggetto costituito da opprotune sequenze di istruzioni di macchina, immediatamente interpretabili ed eseguibili dallo hardware del calcolatore. La traduzione per i moderni calcolatori è un problema complesso, e può influenzare pesantemente le prestazioni ottenibili da una data applicazione. 20072007-08 -6- LA TRADUZIONE Programmare in un linguaggio ad alto livello consente: – – Di programmare con maggiore facilità, Di mantenere l’indipendenza dalla particolare architettura che si sta utilizzando – e quindi garantire la portabilità. Linguaggio interno della macchina: composto da 0 e 1 – segnali che devono attivare particolari unità o trasferire opportune informazioni da un’unità ad un’altra; la rappresentazione binaria è usata sia per le istruzioni sia per i dati; 20072007-08 -7- LA TRADUZIONE Programmare in linguaggio di macchina è praticamente impossibile; il linguaggio di macchina può essere tradotto (mediante una traduzione “1 a 1”) in un linguaggio simbolico, che rende comprensibile al programmatore il significato della singola istruzione ma corrisponde ancora in modo immediato al linguaggio di macchina (ed è quindi dipendente dal calcolatore): si tratta del linguaggio assemblatore (assembly language). 20072007-08 -8- LA TRADUZIONE Es.: il programmatore scrive l’istruzione ad alto livello A+B Il corrispondente in linguaggio assemblatore potrebbe essere add A,B L’istruzione binaria potrebbe essere 1000110010100000 20072007-08 -9- LA TRADUZIONE Programma in linguaggio ad alto livello (es., C) Relazione fra programmi (e linguaggi): Compilatore Programma in linguaggio assemblatore Assemblatore Programma in linguaggio binario 20072007-08 - 10 - LE ISTRUZIONI Linguaggio di macchina: costituito da istruzioni. L’insieme delle istruzioni (Instruction set) costituisce (insieme ad altre informazioni) l’architettura astratta del calcolatore, visibile al programmatore (o al compilatore) e indipendente dalla specifica implementazione interna delle unità funzionali, dai percorsi che trasferiscono informazione fra di esse, etc. 20072007-08 - 11 - LE ISTRUZIONI Le istruzioni devono specificare l’operazione che il calcolatore deve compiere (codice operativo – opcode) e indicare dove si possono trovare i dati su cui l’operazione deve essere compiuta. Insieme delle istruzioni di macchina: devono consentire di tradurre qualunque programma scritto in un linguaggio di alto livello – è indispensabile che particolari classi di istruzioni siano rappresentate. 20072007-08 - 12 - LE CLASSI DI ISTRUZIONI Classi indispensabili: 1. Istruzioni aritmetiche e logiche: qualsiasi calcolatore deve essere in grado di compierle. L’insieme di tali istruzioni ha diversa cardinalità a seconda delle prestazioni che ci si aspetta, delle applicazioni previste, della complessità dell’ALU e dell’unità di controllo. (come minimo occorrono addizione e complementazione per gli interi come operazioni aritmetiche, negazione e una delle operazioni AND e OR come operazioni logiche). 20072007-08 - 13 - Istruzioni aritmetiche e logiche (cont) 1. Un insieme ridotto di istruzioni aritmetiche si traduce in un’ALU più semplice ma in programmi oggetto più lunghi e complessi (e in una più vasta libreria di programmi di sistema) e in un’esecuzione più lenta del programma originale in linguaggio ad alto livello; oggi si tende ad avere tutte le istruzioni aritmetiche in virgola fissa e – almeno in numerose CPU – anche le istruzioni aritmetiche in virgola mobile. 20072007-08 - 14 - LE CLASSI DI ISTRUZIONI 2. È indispensabile che la CPU possa leggere dati dalla memoria e scrivere dati in memoria – occorrono quindi istruzioni di accesso alla memoria (di norma indicate come Load – istruzione che “carica” dalla memoria in un registro interno della CPU – e Store, istruzione che “registra” dalla CPU in memoria). 20072007-08 - 15 - LE CLASSI DI ISTRUZIONI 3. Di norma, l’esecuzione di un normale programma per calcolatore che segua il “paradigma di esecuzione di Von Neumann” è sequenziale: le istruzioni sono registrate in posizioni di memoria consecutive e vengono eseguite nell’ordine in cui sono registrate. A volte occorre però modificare il flusso del controllo – dopo avere eseguito un’istruzione Ik si deve passare a eseguirne una che non la segue direttamente, quindi si deve operare un salto Ö occorrono istruzioni di controllo. 20072007-08 - 16 - LE CLASSI DI ISTRUZIONI 3. In un linguaggio ad alto livello, le istruzioni di controllo si presentano come “cicli” (es. for i = 1,N do…) o come scelta fra alternative (es.: if C then s1 else s2), o ancora come chiamate a procedura o ritorni da procedura. Nel linguaggio interno del calcolatore, i costrutti di controllo devono essere tradotti facendo riferimento a un numero molto ridotto di tipi di istruzioni di controllo. 20072007-08 - 17 - LE CLASSI DI ISTRUZIONI 3. Tipiche istruzioni di controllo sono: a) salti incondizionati: l’istruzione che deve essere eseguita immediatamente dopo quella di salto non è l’istruzione che segue in ordine di programma, ma quella all’indirizzo specificato nell’istruzione stessa – es. jump L1, dove L1 e’ il nome simbolico di un indirizzo (corrispondono a un “go to”): , 20072007-08 - 18 - LE CLASSI DI ISTRUZIONI 3. Tipiche istruzioni di controllo (segue): b) salti condizionati (tipicamente derivati da costrutti di iterazione o da espressioni del tipo ifthen-else): si presentano tipicamente nella forma branch C L1, dove C è una condizione booleana che può essere vera o falsa; Se la condizione C è vera, la prossima istruzione che deve essere letta ed eseguita si trova all’indirizzo L1; Se la condizione C è falsa, la prossima istruzione è quella che segue immediatamente l’istruzione di salto (procedi in sequenza). 20072007-08 - 19 - LE CLASSI DI ISTRUZIONI 3. Tipiche istruzioni di controllo (segue): c) Infine, si dispone di istruzioniu per chiamata a procedura e ritorno da procedura. Le prime si presentano nella forma “call L” , dove L è l’indirtizzo della prima istruzione della procedura; le seconde hanno semplicemente la forma “return”, e sta all’unità di controllo memorizzare opportunamente (al momento della chiamata) l’indirizzo di ritorno 20072007-08 - 20 - LE CLASSI DI ISTRUZIONI 4. Istruzioni di ingresso e uscita: occorre che il processore possa scambiare informazione con le unità periferiche (in molte CPU, è possibile anche “mappare” gli indirizzi delle periferiche su indirizzi di memoria e quindi accedere alle periferiche mediante istruzioni di tipo Load e Store). 5. … e infine un’istruzione fondamentale: nop – un’istruzione che non esegue nulla (acronimo di no operation) ma che a volte è indispensabile! 20072007-08 - 21 - Come reperire i dati? Per le istruzioni “operative” (riguardanti l’ALU) occorre indicare dove reperire gli operandi e dove registrare il risultato; Per le istruzioni che modificano il controllo occorre precisare il punto del programma verso cui si deve spostare il controllo – punto identificato da un indirizzo; In ambedue i casi, il problema si riporta a quello delle modalità di indirizzamento. Esistono numerose modalità di indirizzamento; in genere, un determinato processore ne utilizza solo un sottoinsieme. 20072007-08 - 22 - Le modalità di indirizzamento Gli operandi di un’istruzione aritmetica o logica possono trovarsi: ¾ In un registro interno della CPU – di norma questi sono in numero abbastanza limitato (oggi: da 32 a 256, a seconda delle CPU), quindi possono essere individuati mediante pochi bit; ¾ Nella memoria primaria del calcolatore, che viene vista come un unico spazio di indirizzamento: ci sono vari modi per identificare l’indirizzo. 20072007-08 - 23 - Le modalità di indirizzamento Indirizzo in memoria primaria: può essere specificato come: ¾ Indirizzo assoluto: nell’istruzione si precisa un valore X determinato, l’indirizzo punta alla posizione di memoria M[X] ¾ Indirizzo relativo a registro: l’indirizzo in memoria si calcola come la somma di uno spiazzamento ∆ (offset) e del contenuto di un registro interno della CPU detto in genere registro base (si tratta solitamente di un registro generico Rx). L’indirizzo punta alla posizione M[∆+(Rx)] 20072007-08 - 24 - Le modalità di indirizzamento Ancora: ¾ Indirizzo indiretto da registro: l’indirizzo si trova in un registro interno della CPU, Rx: la parola di memoria si reperisce come M[(Rx)] ; ¾ Indirizzo indiretto da memoria: la parola di memoria indirizzata con altra tecnica (tipicamente, mediante indirizzamento assoluto) contiene l’indirizzo della effettiva parola che contiene il dato: la parola di memoria si reperisce come M[M[X]] 20072007-08 - 25 - Le modalità di indirizzamento Ancora: ¾ Il dato si trova su una area di memoria detta “stack” (pila) gestita in modo particolare – si può accedere sempre e solo al dato che si trova sulla cima della pila – in questo caso non occorre precisare un in dirizzo, dato che questo è “implicito”. Se la pila è ricavata nella memoria principale, la posizione più alta nella pila è indicata da un puntatore (stack pointer). Quando si scrive sulla sommità della pila, il puntatore viene poi “spostato verso l’alto”; quando si legge, il dato viene tolto dalla pila e il puntatore viene “spostato verso il basso”. 20072007-08 - 26 - Le modalità di indirizzamento … sono stati proposti (e in alcuni casi vengono usati) anche molti altri modi di indirizzamento! Si possono utilizzare tutti questi modi con tutti i tipi di istruzioni che fanno un qualche riferimento alla memoria? ¾ Architetture “ortogonali”: praticamente ogni tipo di istruzione può utilizzare ogni tipo di indirizzamento; ¾ In altri casi, modi di indirizzamento diversi sono “riservati” a istruzioni di tipo differente. 20072007-08 - 27 - Le modalità di indirizzamento Es.: l’architettura x86 (progenitrice della famiglia Pentium) è fortemente ortogonale; In molte architetture di CPU, le istruzioni di salto fanno ricorso a un numero limitato di modi di indirizzamento (es., modo indiretto o modo relativo, a volte facendo riferimento al Contatore di Programma come registro base; uso dello stack per le istruzioni di rientro da procedura). 20072007-08 - 28 - Le modalità di indirizzamento Un secondo aspetto delle modalità di indirizzamento (significativa per le istruzioni che fanno riferimento all’ALU): quanti indirizzi si precisano in un’istruzione? Di norma, le operazioni aritmetiche e logiche considerate sono “semplici” – svolgono cioè un’unica operazione aritmetica o logica elementare e hanno due operandi e un risultato Ö soluzione più “naturale”: si indicano esplicitamente gli indirizzi di ambedue gli operandi e del risultato (formato a tre indirizzi). 20072007-08 - 29 - Le modalità di indirizzamento In questo caso, l’istruzione elementare di somma si presenta in codice assembly come add a, b, c dove a è l’indirizzo del risultato e b, c sono gli indirizzi dei due operandi. La struttura interna dell’istruzione sarà del tipo opcode 20072007-08 risult. dato1 - 30 - dato1 Modalità a tre indirizzi L’istruzione vista ora ospita il codice operativo + tre indirizzi… occorrono molti bit! ¾ Se i tre indirizzi possono fare riferimento alla memoria si deve ammettere che l’istruzione sia anche molto “lunga”, (la memoria di lavoro ha grandi dimensioni! E se le parole della memoria sono N, l’indirizzo richiede log2N bit.) ¾ Altrimenti, si deve imporre che alcuni, o tutti, gli indirizzi riguardino solo registri interni della CPU (dato che questi sono pochi, bastano pochi bit per indirizzarli) 20072007-08 - 31 - Modalità a due indirizzi In questa modalità, si precisano solo due indirizzi: l’istruzione elementare di somma si presenta ora in codice assembly come add a, b dove il significato di a e b varia con due possibili alternative. Nella prima, si impone che il risultato venga memorizzato alla fine dell’operazione nella posizione che ospita uno degli operandi: 20072007-08 - 32 - Modalità a due indirizzi La scrittura del risultato in questo caso distrugge il valore dell’operando – se questo deve essere riutilizzato in futuro, occorre “salvarlo” da qualche parte! L’istruzione è più “corta” che nel caso a tre indirizzi, se si accede direttamente alla memoria: il formato interno è opcode 20072007-08 ris./dato1 - 33 - dato2 Modalità a due indirizzi ¾ In alternativa, uno dei due operandi – oppure il risultato – si trova in una posizione fissa, tipicamente in un particolare registro interno della CPU detto accumulatore, il cui indirizzo è quindi “implicito”. In questo caso, i regsirti interni non sono tutti indifferenziati, dato che l’accumulatore vien visto separatamente. Il codice add a, b sottintende – ad esempio – che il risultato si troverà nell’accumulatore; il formato interno è opcode 20072007-08 dato1 - 34 - dato2 Modalità a un solo indirizzo La più ampiamente usata nelle CPU che fanno riferimento alla memoria anche nelle istruzioni operative – in particolare, ampiamente usata nei microprocessori più semplici. Si indica in modo esplicito solo l’indirizzo di uno degli operandi; l’altro operando – e il risultato – si trovano in un registro interno predefinito, di norma l’accumulatore. Il formato interno è opcode 20072007-08 dato1 - 35 - Modalità a un solo indirizzo Quest’ultima modalità permette di accedere alla memoria anche con istruzioni operative relativamente “corte” – il codice oggetto corrispondente a un’istruzione anche semplice in codice sorgente diventa però più lungo. Es.: si debba tradurre A = B + C; sarà necessario: – Trasferire B nell’accumulatore – Eseguire la somma con C – Trasferire il contenuto dell’accumulatore all’indirizzo A. 20072007-08 - 36 - Modalità a zero indirizzi Utilizzata con una memoria organizzata a pila (quindi secondo il principio “Last In – First Out” LIFO): gli indirizzi sono tutti impliciti, dato che i due operandi vengono tolti dalla sommità della pila e il risultato viene depositato sulla sommità della pila. La modalità presume che esistano istruzioni “di servizio” che permettano di gestire la pila. Questa modalità – molto elegante per quanto riguarda l’organizzazione di un programma di traduzione da un linguaggio ad alto livello – in pratica no né oggi utilizzata in CPU reali. 20072007-08 - 37 - Come sono rappresentate le istruzioni nella macchina? In memoria, o comunque nel calcolatore, l’istruzione è registrata come una “stringa” di bit (normalmente una o più “parole”); La struttura dell’istruzione deve permettere all’unità di controllo di decodificarla, cioè assegnare un significato ai vari bit così da attivare correttamente le altre unità e i percorsi di informazione che li collegano. A questo scopo, la stringa di bit che rappresenta l’istruzione va considerata suddivisa in opportuni campi. 20072007-08 - 38 - Come sono rappresentate le istruzioni nella macchina? Le istruzioni in formato binario costituiscono il linguaggio di macchina del calcolatore. Es.: si consideri un calcolatore a tre indirizzi, con parola di 32 bit, nel quale le istruzioni di tipo operativo trovano gli operandi e scrivono il risultato in registri interni alla CPU, facenti parte di un banco di 32 registri. Per identificare un registro occorrono quindi 5 bit. 20072007-08 - 39 - Come sono rappresentate le istruzioni nella macchina? L’istruzione di macchina è strutturata in campi come segue: – Un campo che distingue la classe dell’operazione (nel nostro caso, un’operazione di tipo aritmetico); – Tre campi che ospiteranno l’identificativo degli operandi, posti in un ordine fisso (ad esempio, il primo e il secodno operando e poi il risultato); l’identificativo è qui il numero d’ordoine del registro; – Eventuali altri campi che forniscono alla macchina informazioni addizionali (es., un’ulteriore specificazione della particolare operazione). 20072007-08 - 40 - Come sono rappresentate le istruzioni nella macchina? La nostra add si trasforma quindi come segue: 6 bit Cod. op 20072007-08 5 bit 5 bit 1° oper. 5 bit 2° Risult. oper. destinazi sorgente sorgente one - 41 - 11 bit Campo funzione Come sono rappresentate le istruzioni nella macchina? Si vedrà nel seguito quali modi di indirizzamento si useranno nella CPU di riferimento di questo corso e come tali modalità si traducono nella struttura interna delle istruzioni di macchina. 20072007-08 - 42 - La struttura interna della CPU Indipendentemente dal formato, come viene supportata dalla struttura delle CPU l’esecuzione del programma in linguaggio di macchina? La CPU deve: ¾ Leggere dalla memoria le istruzioni (fase di fetch) ¾ Interpretarle (= decodificare il significato e le operazioni elementari che devono essere comandate alle varie unità interne); ¾ Leggere i dati; ¾ Elaborare i dati ¾ Scrivere i risultati. 20072007-08 - 43 - La struttura interna della CPU Per garantire la corretta esecuzione automatica del programma, l’unità di controllo – dopo avere comandato lettura di un’istruzione – contemporaneamente incrementa il contenuto del contatore di programma in modo che sia pronto a indicare l’istruzione successiva (nel caso il flusso del controllo debba essere modificato in conseguenza di un’istruzione di controllo, tale valore verrà opportunamente sostituito nel corso dell’esecuzione dell’istruzione). 20072007-08 - 44 - La struttura interna della CPU In questo modo, non appena l’esecuzione di un’istruzione è terminata (si vedrà in seguito il dettaglio di decodifica ed esecuzione), nel contatore di programma è già pronto l’indirizzo della prossima istruzione da eseguire, quindi si ripèrende automaticamente la sequenza lettura dell’istruzione – decodifica… etc. 20072007-08 - 45 - La struttura interna del calcolatore Nello schema di Von Neumann, la CPU è collegata alle altre unità del sistema ((Memoria, I/O) mediante interconnessioni dirette; oggi tale soluzione non è più adottata Lo schema elementare di interconnessione è organizzato intorno a un Bus di Sistema che trasferisce sulle sue varie sezioni i dati, gli indirizzi, i segnali di controllo. 20072007-08 - 46 - Il collegamento fra CPU e sistema CPU registri ALU Unità di controllo Bus degli indirizzi Bus di controllo 20072007-08 - 47 - Bus di sistema Bus dei dati La struttura interna della CPU Per leggere un’istruzione dalla memoria, la CPU: ¾ ¾ Trasferisce l’indirizzo dell’istruzione (contenuto nel Contatore di Programma, che è uno dei registri interni) sul bus degli indirizzi; Invia alla memoria il comando di lettura (tramite opportune linee del bus di controllo); In risposta, la memoria estrae la parola richiesta e: ¾ ¾ 20072007-08 Porta l’istruzione sul bus dei dati Segnala alla CPU - mediante il bus di controllo – che l’istruzione è disponibile. - 48 - La struttura interna della CPU Ogni bus è costituito da un certo numero di linee, ognuna delle quali trasporta un singolo bit; Ogni linea del bus degli indirizzi trasporta un bit dell’indirizzo; analogamente, ogni linea del bus dati trasporta un bit di dato – la differenza fra due linee corrisponde solo alla posizione del bit; Le diverse linee del bus di controllo sono invece associate a funzionalità diverse – corrispondono a segnali di controllo con significati diversi, scambiati fra le varie unità del sistema. 20072007-08 - 49 - La struttura interna della CPU All’interno della CPU sono presenti dei registri, alcuni dei quali sono specializzati e non “visibili al programmatore” (non esistono istruzioni specifiche che permettano di scrivevi un valore arbitrario o di leggerne il contenuto): tali registri sono utilizzati fondamentalmente dalla unità di controllo; Esistono inoltre registri di tipo generale, che fungono da “memoria di lavoro” interna alla CPU. 20072007-08 - 50 - I registri interni Come minimo, esiste un registro visibile al programmatore (detto in questo caso “accumulatore”); Nelle CPU moderne, esiste un certo numero di registri general purpose visibili al programmatore e indifferenziati (hanno cioè tutti le stesse funzioni e capacità, e le stesse dimensioni, uguali a quelle di una parola di memoria) organizzati in un register file (o “banco di registri”) 20072007-08 - 51 - Il register file Struttura generale di un register file: Porta di lettura Register file Indirizzo (= numero d’ordine del registro) 20072007-08 Porta di scrittura - 52 - Il register file L’ indirizzo (costituito da log2 k bit, se k sono i registri nel banco) permette di selezionare il particolare registro cui si vuole accedere; Alla porta di lettura si legge il contenuto del registro selezionato; Alla porta di scrittura si trasferisce da un’altra unità (es., dalla memoria, o dall’uscita dell’ALU) il valore che si vuole scrivere nel registro selezionato; 20072007-08 - 53 - Il register file In genere, è possibile accedere simultaneamente in lettura e in scrittura a due registri (non necessariamente diversi) o meglio ancora leggere simultaneamente da più registri (es., due) e scrivere in un registro. Il register file costituisce la memoria più “vicina” alla CPU (al “massimo livello” nella gerarchia di memorie); 20072007-08 - 54 - Il register file Decidere il numero dei registri nel register file e il numero di porte di lettura e scrittura sono scelte molto importanti al momento del progetto di una CPU;un numero elevato di registri aumenta la flessibilità e le opzioni del programmatore (o del compilatore) ma cresce il numero dei bit di indirizzamento che compaiono nelle istruzioni e l’accesso al register file diventa più lento! 20072007-08 - 55 - Il register file Nelle CPU moderne: da 32 a 256 registri nel Register File; Spesso è possibile combinare due registri per ospitare una “doppia parola” (ad esempio, per fare calcoli “in doppia precisione”) etc. 20072007-08 - 56 - Altri registri Registro/i di “flag” o di “condition code”: ¾ ¾ ¾ 20072007-08 Insieme di singoli bit (ognuno costituisce una “flag”) il cui valore viene implicitamente posizionato da una particolare condizione che si verifica durante l’esecuzione di determinate istruzioni (es., il confronto fra i contenuti di due registri, oppure il fatto che il risultato di un’operazione aritmetica sia 0, etc.) Possono essere implicitamente letti dal programma (es., in un’ istruzione di salto condizionato vincolato a una delle condizioni); Di norma i bit di questo registro non possono essere scritti in modo esplicito dal programma. - 57 - Registri di controllo e di stato Contatore di Programma (PC) Registro Istruzione (vi viene portata l’istruzione appena letta, perché l’unità di controllo possa interpretarla e comandarne l’esecuzione); Registro di indirizzamento della memoria (MAR); Registro di interfaccia con la memoria (Memory Buffer); E altri registri (es., Stack Pointer, Program Status Word) di cui si parlerà quando necessario. 20072007-08 - 58 - Struttura interna della CPU È di nuovo organizzata intorno a un sistema di bus: Bus interno della CPU ALU 20072007-08 - 59 - Register file Unità di contr. Le caratteristiche dell’insieme di istruzioni Due alternative fondamentali: ¾ ¾ 20072007-08 Architetture “con riferimento alla memoria” – sostanzialmente ortogonali: anche le istruzioni operative possono accedere direttamente a dati in memoria (in lettura o in scrittura). Architetture di tipo “registro-registro” (dette anche “Load-Store”): solo le istruzioni Load e Store possono accedere direttamente alla memoria, le istruzioni operative possono fare riferimento solo al contenuto dei registri del register file (oltre che su valori immediati). - 60 - Architetture “con riferimento alla memoria” Consentono programmi in linguaggio macchina più compatti; Le diverse istruzioni possono richiedere un numero diverso di parole di memoria per potere ospitare (oltre al codice operativo) indirizzi di un numero di bit sufficiente ad indirizzare una memoria di dimensioni abbastanza grande Ö l’unità di controllo risulta più complessa (la lettura di un’istruzione può estendersi su più parole di memoria…); Lettura ed esecuzione delle diverse istruzioni hanno caratteristiche “irregolari”. 20072007-08 - 61 - Architetture “registro-registro” Il programma oggetto risulta più lungo; la semplice istruzione “A=B+C” con dati in memoria e risultato che deve anch’esso essere scritto in memoria si traduce nella sequenza: ¾ ¾ ¾ ¾ 20072007-08 leggi B dalla memoria in un registro RB; leggi C dalla memoria in un registro RC; somma i contenuti di RB ed RC e scrivi il risultato in un registro RA; scrivi il valore contenuto in RA in memoria. - 62 - Architetture “registro-registro” Ma… ¾ ¾ ¾ 20072007-08 Tutte le istruzioni hanno la stessa lunghezza; L’unità di controllo è nettamente più semplice; Lettura ed esecuzione delle diverse istruzioni hanno caratteristiche fortemente “regolari” – questo porta a soluzioni ottimizzate della CPU che permettono prestazioni molto più elevate (= esecuzione più veloce dell’intero programma). - 63 - L’architettura di riferimento Si farà riferimento all’architettura MIPS – progettata inizialmente da un gruppo guidato da Hennessy e Patterson (delle università di Berkeley e Stanford), poi diventata un’architettura commerciale (oggi per sistemi embedded): essenzialmente un’architettura registro-registro. Le istruzioni operative precisano tipicamente gli indirizzi dei due operandi e del risultato come registri – l’unica alternativa è che uno degli operandi sia un “immediato” (una costante). 20072007-08 - 64 - L’architettura di riferimento MIPS ha un banco di 32 registri; 5 bit bastano per indirizzare un registro; La notazione $x verrà usata per indicare il registro x (quindi $1, $2…) Es.: sia data l’espressione f = (g+h) – (i+j) se ne vuole la traduzione nell’assembler del MIPS: 20072007-08 - 65 - MIPS: un esempio di assembler Dapprima si traduce l’espressione complessa in una sequenza di operazioni aritmetiche semplici (binarie), introducendo variabili ausiliarie e avendo cura di scegliere una traduzione che minimizzi la lunghezza del codice oggetto: quindi t0 = g+h t1 = i+j f = t0 – t1 20072007-08 - 66 - MIPS: un esempio di assembler Si supponga ora che il registro $1 contenga la variabile g, $2 la variabile h, $3 la variabile i, $4 la variabile i, e che il registro $10 debba contenere il risultato f: la traduzione nel linguaggio assembler sarà: add $5, $1, $2 # t0 si trova in $5 add $6, $3, $2 # t1 si trova in $6 sub $10, $5, $6 20072007-08 - 67 - MIPS: i riferimenti alla memoria Come già detto, solo le istruzioni specifiche di lettura da memoria e scrittura in memoria (Load e Store) possono accedere alla memoria; l’indirizzo cui accedere viene costruito mediante indirizzamento relativo, indicando uno spiazzamento rispetto a un registro base (un registro del register file, scelto liberamente) in cui è memorizzato il valore-base dell’indirizzo. 20072007-08 - 68 - MIPS: i riferimenti alla memoria Es.: data l’espressione in C g = h + A[8] si supponga che la variabile g si trovi nel registro $2; occorre portare in un registro il valore A[8], che si trova in memoria. Si supponga che l’indirizzo-base del vettore A si trovi nel registro $3; la sequenza di istruzioni sarà: lw $4, 8($3) # la parola viene letta add $1, $2, $4 20072007-08 - 69 - MIPS: i riferimenti alla memoria L’istruzione lw sta per “load word” – leggi un’intera parola di 32 bit. In realtà, la memoria del MIPS (come di molti calcolatori…) è organizzata a byte – gruppi di otto bit. Gli indirizzi delle parole iniziano quindi sempre a distanza quattro: nell’esempio appena fatto, il codice macchina darà uno spiazzamento pari a 32 (quattro byte), quindi la sequenza reale sarà: lw $4, 32($3) add $1, $2, $4 20072007-08 - 70 - MIPS: il formato interno delle istruzioni Si sono visti due esempi di istruzioni: quale è l’effettiva organizzazione della parola che rappresenta un’istruzione? I 32 bit che costituiscono una parola vengono numerati da sinistra a destra, da 0 a 31 e organizzati in “campi” (gruppi di bit consecutivi cui viene assegnato un particolare significato) 20072007-08 - 71 - MIPS: il formato interno delle istruzioni Per le istruzioni che utilizzano il contenuto di registri per istruzioni aritmetico-logico (istruzioni di tipo R) il formato è: op 6 bit rs rt rd 5 bit 5 bit 5 bit shamt funct 5 bit 6 bit dove op è il codice operativo fondamentale, rs il registro sorgente del primo operando, rt il registro sorgente del secondo, rd il registro destinazione del risultato, shamt (shift amount) verrà discusso in seguito, funct specifica la variante dell’operazione il cui tipo è indicato da op. 20072007-08 - 72 - MIPS: il formato interno delle istruzioni Il precedente formato non è utile quando si vogliano utilizzare campi più lunghi di 5 bit; ad esempio, una Load o una Store utilizzano uno spiazzamento che – per essere significativo – non può limitarsi a 5 bit. Si introduce quindi un nuovo formato, mantenendo sempre l’istruzione di 32 bit (formato I, dove I sta per Immediato), utile sia per le istruzioni di riferimento a memoria sia per quelle che utilizzano una costante (indirizzamento immediato): op 6 bit 20072007-08 rs rt 5 bit 5 bit Costante o indirizzo 16 bit - 73 - MIPS: il formato delle istruzioni di tipo I Es.: l’istruzione lw $5, 32($3) avrà la seguente struttura interna: lw 6 bit $3 $5 5 bit 5 bit 32 16 bit si noti: ora nel campo rs si specifica il registro base, mentre nel campo rt si indica il registro destinazione dell’operazione di lettura. 20072007-08 - 74 - MIPS: il formato interno delle istruzioni Le istruzioni che modificano il flusso del controllo fanno ricorso a indirizzamento relativo. Consideriamo un primo caso: Si confrontano i valori di due registri del register file (possono essere uguali o non uguali) e in conseguenza del risultato si procede in sequenza oppure si “salta” a un indirizzo calcolato come somma dello spiazzamento indicato nell’istruzione e del contenuto del Program Counter. IL formato è op 6 bit 20072007-08 rs rt 5 bit 5 bit spiazzamento 16 bit - 75 - MIPS: il formato interno delle istruzioni Es.: sia data l’istruzione beq $1, $2, L1 l’istruzione in assembler indica che se il confronto fra i due registri dà risultato “uguale” l’esecuzione deve passare all’indirizzo L1, altrimenti deve procedere in sequenza dopo l’istruzione di salto condizionato. L’indirizzo nell’istruzione di macchina viene precisato come somma algebrica di uno spiazzamento di 16 bit e del PC. rt spiazzamento rs op 6 bit 20072007-08 5 bit 16 bit 5 bit - 76 - MIPS: il formato interno delle istruzioni Analogamente, si può imporre un salto condizionato del tipo bne – il salto viene effettuato se i due registri hanno contenuto diverso. Sia data l’istruzione in C. if (i==j) f = g+ h ; else f = g – h e si supponga che i e j si trovino rispettivamente nei registri 3 e 4, mentre f deve andare nel registro 5, g e h si trovano nei registri 1 e 2: può valere la pena di tracciare innanzitutto un diagramma di flusso delle operazioni elementari corrispondenti all’istruzione: 20072007-08 - 77 - MIPS: il formato interno delle istruzioni vero else i=j? F=g+h F=g-h Exit Il codice assembler corrispondente sarà: 20072007-08 - 78 - MIPS: le istruzioni di salto condizionato Si utilizza innanzitutto un’istruzione di salto condizionato, dove come condizione si usa la verifica che i valori contenuti nei registri 3 e 4 siano diversi – se la condizione è vera, si deve passare a eseguire le istruzioni corrispondenti al ramo “else”: quindi: bne $3, $4, Else 20072007-08 # Else è l’etichetta della destinazione se la condizione if è vera - 79 - MIPS: le istruzioni di salto condizionato Se invece la condizione nell’istruzione bne è falsa, si continua in sequenza (ramo “vero” nello schema di flusso) sommando le variabili contenute nei registri $1 e $2; al termine di questa operazione si deve passare alla “chiusura” (indirizzo simbolico exit) con un’istruzione di salto incondizionato. Quindi il ramo “vero” dello schema di flusso si traduce in add $5, $1, $2 j exit # si deve saltare alla destinazione comune delle due diramazioni 20072007-08 - 80 - MIPS: le istruzioni di salto condizionato concludendo, il segmento di programma assembly è bne $3, $4, Else # Else è l’etichetta della destinazione se la condizione if è falsa add $5, $1, $2 # la condizione if è vera j exit # si deve saltare alla destinazione comune delle due diramazioni Else: sub $5, $1, $2 # ramo else Exit: …. 20072007-08 - 81 - MIPS: le istruzioni di salto Il salto incondizionato, jump (j) fa si che il contenuto del contatore di programma venga modificato – sostituendolo con quello precisato nell’istruzione – indipendentemente da qualsiasi condizione. Il formato interno sarà ancora diverso dai precedenti; accanto al codice operativo si indicano 26 bit che vanno concatenati con i sei bit più significativi del PC. op 6 bit 20072007-08 spiazzamento 26 bit - 82 - Come gestire le procedure? Una chiamata alla procedura implica: ¾ ¾ Il passaggio dei parametri Il passaggio del controllo all’indirizzo iniziale della procedura Così come il ritorno implica un passaggio di risultati e il trasferimento del controllo alla prima istruzione immediatamente successiva a quella di chiamata a procedura. Come implementare queste operazioni nello hardware? 20072007-08 - 83 - Come gestire le procedure? IL passaggio dei parametri viene gestito sfruttando i registri; il cambiamento del flusso del controllo richiede qualche aggiunta allo hardware: Chiamare una procedura implica la necessità di salvare l’indirizzo di rientro – una procedura può essere chiamata da molti, diversi punti di uno stesso programma, e al termine della sua esecuzione si deve ogni volta tornare all’istruzione del progamma chiamante immediatamente successiva alla chiamata! 20072007-08 - 84 - Come gestire le procedure? È chiaro che una semplice istruzione di salto incondizionato non è sufficiente, dato che non “salva” l’indirizzo dell’istruzione successiva a quella di chiamata. Si introduce una nuova istruzione “jump-and-link” (jal) il cui formato è simile a quello di un salto incondizionato: jal 6 bit 20072007-08 spiazzamento 26 bit - 85 - Come gestire le procedure? Il nuovo indirizzo viene ancora creato concatenando lo spiazzamento coi sei bit più significativi del program counter; L’operazione “link” consiste nel memorizzare in un apposito registro $ra l’indirizzo di ritorno (che coincide con il contenuto del PC). L’istruzione di “ritorno” che conclude la procedura sarà un salto incondizionato all’indirizzo contenuto nel registro $ra (si noti: in questo caso nel registro si trova l’indirizzo intero!) 20072007-08 - 86 - Come gestire le procedure? E se ci sono procedure “annidate”? La soluzione ora indicata non darebbe buon esito – alla chiamata della procedura più interna il “salvataggio” del relativo indirizzo di rientro distruggerebbe l’indirizzo di rientro dalla procedura più esterna! Per gestire più procedure annidate, o permettere trasferimenti di parametri più complessi, la CPU può far uso di uno stack (pila). 20072007-08 - 87 - Come gestire le procedure? Stack: un’area della memoria di lavoro (definita in fase di inizializzazione del sistema) cui si accede mediante un altro registro speciale, detto stack pointer (puntatore alla pila). Lo stack viene gestito “come una pila di piatti”: il puntatore indica l’indirizzo in memoria che corrisponde alla “cima” della pila. 20072007-08 - 88 - Come gestire le procedure? Le operazioni possibili consistono 1. nel “porre” un dato sulla pila – operazione detta push, istruzione in cui si indica solo il nome del registro il cui contenuto va trasferito sulla pila (l’indirizzo di memoria è implicito, essendo contenuto nel puntatore); al termine dell’istruzione, il puntatore viene automaticamente incrementato per puntare alla prima posizione libera nella pila; 2. Nel “togliere” un dato dalla pila – operazione detta pop; al termine dell’istruzione, il puntatore viene automaticamente decrementato (è “come se” il dato fosse stato fisicamente eliminato). 20072007-08 - 89 - Come gestire le procedure? In presenza di procedure annidate, il programmatore (o il compilatore) salva sulla pila l’indirizzo di ritorno della procedura più esterna; procedendo in ordine, è chiaro che la sequenza push-pop garantisce la sequenza corretta salvataggio – utilizzo degli indiriuzzi di rientro. La pila viene usata anche per il passaggio dei parametri. 20072007-08 - 90 - Riassumendo: i modi di indirizzamento del MIPS Indirizzamento a registro – l’operando è contentuo in un registro; Indirizzamento mediante spiazzamento l’operando è in una posizione di memoria il cui indirizzo si ottiene sommando lo spiazzamento al contenuto di un registro base, Indirizzamento immediato: l’operando è una costante indicato direttamente nell’istruzione; Indirizzamento relativo al PC: l’indirizzo è la somma del contenuto del PC e di una costante contenuta nell’istruzione; Indirizzamento pseudodiretto: l’indirizzo destinazione di un salto incondizionato è costituito dai 26 bit meno significativi dell’istruzione concatenati con i sei bit più significativi del PC. 20072007-08 - 91 - Riassumendo: i modi di indirizzamento del MIPS Indirizzamento immediato: op rs rt immediato Indirizzamento a registro op rs rt rd shamt funct registro 20072007-08 - 92 - Riassumendo: i modi di indirizzamento del MIPS Indirizzamento mediante spiazzamento: op rs rt spiazzamento memoria byte registro 20072007-08 - 93 - parola Riassumendo: i modi di indirizzamento del MIPS Indirizzamento relativo al PC: op rs rt spiazzamento memoria parola PC 20072007-08 - 94 - Riassumendo: i modi di indirizzamento del MIPS Indirizzamento psudodiretto: op indirizzo memoria : PC 20072007-08 - 95 - parola Alcune considerazioni I salti condizionati puntano a indirizzi a distanza di ±215 parole dall’istruzione corrente (di fatto, dall’indirizzo della istruzione successiva al salto stesso); di fatto, la statistica dimostra che la destinazione di un salto condizionato è di norma anche molto vicina al salto stesso (comunque si indica la distanza come numero di parole, non di byte); Salti incondizionati, chiamate a e ritorni da procedura hanno più probabilità di puntare a indirizzi anche notevolmente lontani (anche qui, la distanza viene data in parole) – il campo di 26 bit nelle istruzioni permette di esplorare un campo di 228 bytes! 20072007-08 - 96 - Alcune considerazioni Le costanti usate di norma sono piccole (fatto verificato statisticamente) – 16 bit sono sufficienti per specificarle. Esistono istruzioni particolari che permettono anche di costruire costanti di 32 bit, ma non sono essenziali per i nostri scopi, quindi non si approfondiranno! Particolari tipi di istruzioni possono usare più modi di indirizzamento; ad esempio, per la somma esistono sia la forma add rd, rs1, rs2 sia la forma addi rd, rs1, costante 20072007-08 - 97 -