Informatica A.A. 2009/2010 Parte 2 L’Elaboratore Corso A: Prof. Stefano Berardi Corso B: Prof. Ugo de’ Liguoro
John Von Neumann 2-Elaboratore Budapest, 28 dicembre Washington, 8 febbraio 1957
Indice Parte 2: l’Elaboratore 1.Architettura dell’elaboratore: la macchina di von Neuman 2.La memoria: registri, memoria centrale o RAM, memoria di massa 3.L’esecuzione di un calcolo: il ciclo fetch- execute 4.Assembly: un linguaggio di programmazione “a livello macchina”. 5.Linguaggi di programmazione di alto livello: C/C++, Java, ecc.. La Compilazione.
1. L’architettura di un calcolatore Per meglio comprendere le nozioni C++ di “indirizzo”, “contatore di programma” e “istruzione di salto” è utile conoscere l’architettura di von Neuman che sta alla base dei moderni calcolatori. Siamo fatti così! CPU input output RAM
Per confronto, descriviamo un “calcolatore umano” Come si organizza un essere umano per eseguire un algoritmo? Ecco una possibile risposta. 2-Elaboratore Carta da minuta per scrivere i risultati intermedi Procedura: fai … Dati: a,b,c Risultati : x,y,z
Scomponiamo il nostro “calcolatore umano” Carta da minuta per scrivere i risultati intermedi Procedura: fai … Dati: a,b,c Risultati : x,y,z Memoria Ingresso UscitaUnità di calcoloControllo
La memoria contiene sia i passi dell’algoritmo che dobbiamo eseguire (nel il foglietto con su scritto “procedura”), sia tutti i risultati iniziali, intermedi e finali (nella “carta da minuta”). L’ingresso contiene i dati iniziali del problema. Il controllo decide cosa fare ad ogni passo. L’unità di calcolo è la calcolatrice che stiamo usando. Le memorie dell’unità di calcolo (della calcolatrice nel nostro esempio) sono detti registri. L’uscita è il risultato del calcolo. Le componenti del nostro “calcolatore umano”
La macchina di von Neumann Memoria centrale o RAM Unità di controllo Unità di calcolo logico aritmetica (ALU) Ingresso/Uscita (I/O) CPU (le sue memorie sono dette registri) istruzionidati Una macchina descritta da von Neuman ha le stesse componenti del nostro “calcolatore umano ”
2. Memoria centrale (RAM) e memoria di massa Memorie di massa: una biblioteca RAM: una postazione per la consultazione Oltre alla memoria RAM, il computer ha la memoria di massa. È come una biblioteca che possiamo consultare nella memoria RAM.
Immagini della memoria centrale (RAM) e della memoria di massa Memorie di massa Memoria centrale Hard Disk RAM Lenta ma molto capiente e persistente Veloce ma poco capiente e non persistente 2-Elaboratore
La memoria centrale (RAM) La memoria RAM è una sequenza lineare di bytes, ovvero di liste di otto cifre 0, 1. I bytes sono numerati con interi 0, 1, 2, …, detti indirizzi di memoria. Un byte o un gruppo di bytes nella RAM si può leggere come un intero tra 0 e 255, ma può rappresentare molte cose (tutte essenziali in programmazione): una istruzione del linguaggio della macchina (per esempio: ADD) un numero intero o reale l’indirizzo di memoria di: una istruzione, oppure di un numero, oppure un’altro indirizzo.
Un’immagine della RAM come lista di bytes … Un byte ha sempre un valore (binario) tra 0 e 255: non esistono celle di memoria “indefinite”
Come si accede alla RAM? L’accesso a una cella della memoria RAM avviene interpretando ogni cifra 0, 1 dell’indirizzo della cella mediante le biforcazioni in un “albero”. L’accesso richiede tempo uguale per tutte le celle 2-Elaboratore
Un esempio di un gruppo di istruzioni contenute nella RAM ADD k... ADD(numero istr. somma) ADD è il numero dell’istr. somma, i cui argomenti sono due memorie numerate 428 e 884, con risultato scritto nella memoria numero 800. Nota: sommare le memorie di numero 428 e 884 non significa sommare 428 e 884! Magari la A fianco, vediamo 4 bytes consecutivi della RAM che contengono : memoria numero 428 contiene 42 e la memoria numero 884 contiene non è il risultato ma il numero della memoria in cui scriviamo il risultato 54
3. Il ciclo di calcolo della macchina di von Neumann Ogni singolo calcolo richiede tipicamente un ciclo di cinque passi: 1.“Fetch” istruzione (copia l’instruzione dalla RAM in un registro) 2.Decodifica istruzione 3.“Fetch” Dati (copia i dati dalla RAM in registri) 4.Esecuzione Istruzione, con risultato in un registro. 5.Copia del risultato all’indietro, nella RAM 2-Elaboratore
Il ciclo Fetch/Execute 2-Elaboratore Come esempio vedremo come un passo del ciclo Fetch/Execute esegue la somma (42+12)
Unità di controllo (CPU) Implementa il ciclo macchina direttamente attraverso i circuiti o hardware. I suoi circuiti recuperano un’istruzione dalla memoria ed eseguono altre operazioni del ciclo 1.un’istruzione tipica è per es.: ADD quest’istruzione chiede che i numeri memorizzati negli indirizzi 428 e 884 siano sommati dalla ALU e che il risultato sia inserito nell’indirizzo il passo “Fetch Dati” estrae i due valori; dopo aver effettuato la somma il passo Restituzione Risultato inserirà la somma nell’indirizzo 800
Unità Aritmetico/Logica ALU È parte della CPU. Esegue tutti i calcoli nei registri ma dispone di poca memoria (i soli registri). Generalmente la ALU è responsabile del passo del ciclo macchina denominato Esecuzione Istruzione Un circuito nella ALU può sommare due numeri. Ci sono anche circuiti dedicati alla moltiplicazione, al confronto di due numeri ecc. Le istruzioni di puro trasferimento dei dati da e verso la RAM non usano la ALU. 2-Elaboratore
Relazione tra ALU e RAM Il passo del ciclo macchina Fetch Dati recupera dalla RAM i valori necessari alla ALU (i valori degli operandi). Quando la ALU ha completato l’operazione, il passo Restituzione Risultato trasferisce il risultato (somma o prodotto o qualche altro valore) dalla ALU in un indirizzo di memoria della RAM specificato nell’istruzione 2-Elaboratore
Il Program Counter (PC) Per determinare l’istruzione successiva nell’esecuzione di un programma, il suo indirizzo è memorizzato in un registro della UC chiamato Program Counter (PC) o contatore di programma. Se (poniamo) le istruzioni occupano 4 byte di memoria, l’istruzione successiva dovrebbe essere PC + 4 Il PC è incrementato di 4: quando il ciclo macchina ritornerà al passo Fetch Istruzione, il PC “indicherà” l’istruzione successiva 2-Elaboratore
Istruzioni di “salto” per il PC (Program Counter) In programmazione, è essenziale il fatto che una istruzione può includere l’indirizzo dell’istruzione successiva. Queste istruzioni sono dette “salti” o jumps. Il salto può essere incondizionato se avviene sempre, condizionato se avviene solo quando una certa condizione è vera. Quando eseguiamo una istruzione di “salto” il contatore di programma, invece di aggiungere 4 automaticamente, "salta" alla locazione specificata, magari a un miliardo di bytes di distanza. 2-Elaboratore
Un esempio: il calcolo di Il computer interpreta i nostri comandi, espressi nel suo linguaggio fatto di 0 e 1 Prima che il ciclo macchina inizi, qualche locazione di memoria e il PC sono visibili nell’unità di controllo Vediamo come il ciclo Fetch/Execute calcola , supponendo che il due numeri si trovino nelle memorie numero 428 e 884, e che il risultato, 54, venga scritto nella memoria 800. Indichiamo sempre con ADD il numero dell’istruzione “somma”.
Lo stato del computer all’inizio dell’istruzione ADD Supponiamo PC=2200. Il controllo sta eseguendo l’istruzione 2200, che richiede di sommare le memorie numero 428 e 884, e di scrivere il risultato nella memoria Elaboratore PC: ADD 800, 428, 884
Passo 1: Fetch istruzioni L’esecuzione comincia trasferendo dalla memoria a un registro dell’unità di controllo l’istruzione ADD, rappresentata da un numero, e contenuta nell’indirizzo 2200 specificato dal PC, quindi gli indirizzi 800, 428, ADD 800, 428, 884 PC: 2200
Passi 2,3: Decodifica/Fetch dati I bits dell’istruzione ADD, decodificati dal controllo, attivano un circuito della ALU capace di eseguire l’operazione di somma (al numero dell’istruzione associamo il circuito che esegue l’istruzione) Una volta fatto questo, il controllo incrementa il PC da 2200 a 2204, per preparare la lettura dell’istruzione successiva. Nel passo dopo, il controllo cerca gli argomenti dell’addizione, 42 e 12, nelle memorie RAM di numero 428 e 884, quindi li copia nei registri del circuito somma dentro l’unita’ logico-aritmetica. 2-Elaboratore
Il controllo copia l’operazione e i dati dell’operazione nell’ALU 2-Elaboratore Circuito somma [ ] ADD 800, 428, 884 PC: :ADD 800, 428, 884 Circuito somma [42] [12] [ ] ADD 800, 428, 884 PC: : 428: 884: ADD 800, 428,
Passo 4: Esecuzione istruzioni Esecuzione Istruzione. Finalmente arriviamo al passo in cui sono effettivamente eseguiti i calcoli, la somma di 42 e 12 in questo caso. Non era possibile eseguire i calcoli nella RAM, che è solo capace di ricordare e ricopiare. È invece possibile eseguire i calcoli dopo aver copiato il numero dell’operazione e i suoi argomenti nell’unita’ logico-aritmetica ALU. 2-Elaboratore
Circuito somma [42] [12] [ 54] ADD 800, 428, 884 PC: : 428: 884: 800: ADD 800, 428, l’ALU inserisce il risultato della somma in un registro
Passo 5: Restituzione risultato Restituzione Risultato. L’unita’ logico- aritmetica non è capace di ricordare molti dati: per questo c’è la RAM. Il controllo deve quindi ricopiare il risultato della somma nella locazione di memoria RAM specificata dall’indirizzo 800 Una volta concluso questo passo, il ciclo ricomincia 2-Elaboratore
Circuito somma [42] [12] [ 54] ADD 800, 428, 884 PC: : 428: 884: 800: ADD 800, 428, l’ALU restituisce il risultato della somma nella RAM
4. Il linguaggio assembly La macchina vede le istruzioni come una lunga sequenza di “parole” o gruppi di 4 bytes. Ogni sistema operativo (per es., Windows), invece, ha un proprio linguaggio assembly, che rappresenta il linguaggio macchina usando lettere e numeri in luogo del codice binario (per es., ADD per la somma oppure JB per l’istruzione di salto condizionato). Ogni sistema operativo ha un programma (chiamato assembler) che converte il programma assembly in cifre binarie. Un programma assembly è scritto in un linguaggio di abbreviazioni di facile traduzione in binario.
Esempio di programma in assembly con un solo registro dati: AX COPY AX M0 L1 ADD AX M1 OUT AX CMP AX M10 JB L1 Tra le istruzioni elencate sopra, è particolarmente importante l’istruzione JB L1 di “salto” del program counter all’indirizzo L1 di una istruzione anche molto lontana del programma quando una precedente condizione è vera. Copia AX:=M0 Somma AX:=AX+M1 Stampa di AX Confronto tra AX, M10 “salto del contatore all’istruz. L1 se il confronto precedente è vero
Una CPU semplificata Instruction Pointer (PC o IP) Instruction Register (IR) Condition flag (CF) Accumulator (AX) PC indirizzo istruzione da eseguire istruzione da associare a un circuito Contiene “true” o “false” Unico registro dati AX. Contiene il valore corrente del calcolo 2-Elaboratore
Un esempio di linguaggio Assembly IstruzioneFormatoAzione Copia dalla mem. COPY AX mem AX := mem Copia nella mem. COPY mem AX mem := AX Somma ADD AX mem AX := AX + mem Sottrazione SUB AX mem AX := AX – mem Moltiplicazione MUL AX mem AX := AX * mem Divisione DIV AX mem AX := AX / mem Confronto (assegna un booleano a CF) CMP AX mem CF := TRUE se AX < mem CF := FALSE altrimenti Salto incondizionato JMP label PC := label Salto condizionato JB label PC := label se CF = TRUE Salto condizionato JNB label PC := label se CF = FALSE Input IN AX Inserisce l’ingresso in AX Output OUT AX Stampa il contenuto di AX In assenza di istruzioni particolari, all’indirizzo PC si assegna PC:=PC+1
Un programma ASSEMBLY COPY AX M0 L1 ADD AX M1 OUT AX CMP AX M10 JB L1 1.Copia in AX il contenuto di M0 2.Somma ad AX il contenuto di M1 sovrascrivendolo ad AX 3.Stampa il contenuto di AX 4.Confronta il contenuto di AX con quello di M10 5.Se al passo 4 AX < M10 allora fa saltare il contatore di programma all’istruzione L1 Le istruzioni ASSEMBLY per eseguire AX:=M0 e ripetere l’assegnazione AX=AX+M1 finche’ AX < M10 Trovate un simulatore per questo ASSEMBLY nel sito del corso 2-Elaboratore
5. Linguaggi di programmazione Programmare in assembly è complicato, perché, necessariamente, l’uso di istruzioni molto elementari trasforma in lunghe sequenze di codice anche delle semplici operazioni: stampa a*b + d*c; COPY AX a MUL AX b COPY temp AX COPY AX d MUL AX c ADD AX temp OUT AX Operazione Codice assembly 2-Elaboratore
Linguaggi di programmazione Per ovviare sono stati introdotti i linguaggi di programmazione, lingue artificiali per la definizione di programmi, simili all’algebra e ad un rudimentale inglese: Pascal, C, C++, Java, C#, … intermedie tra il linguaggio umano e il linguaggio Assembly, che a sua volta deve venire tradotto in liste di 0, 1 (l’unico linguaggio che la macchina capisca!) 2-Elaboratore
Esempio di codice in un linguaggio d’alto livello I programmi in C++, Java, ecc. hanno questo aspetto.
La compilazione Il codice di un linguaggio di alto livello, come il C/C++, non è immediatamente eseguibile. Prima occorre tradurlo in Assembler, creando un programma “eseguibile” (in Windows, un file “.exe”), poi in linguaggio macchina. Alla prima traduzione provvede il compilatore, alla seconda il sistema operativo. Due macchine con lo stesso sistema operativo capiscono lo stesso linguaggio Assembly, e quindi gli stessi file “eseguibili”, anche se il loro linguaggio macchina è diverso.
L’effetto della compilazione total = num1+num1; 2-Elaboratore ADD Le tre forme principali di codifica del software: il linguaggio di programmazione, il linguaggio assembly (del sistema operativo) e il linguaggio macchina. Linguaggio di programmazione Linguaggio assembler Rappresentazione binaria
Le fasi della compilazione 1.Fase 1. Si scrive il testo del programma, ad es. in C++, utilizzando un text editor: il risultato è il programma sorgente (file.cpp). 2.Fase 2. Questo file è dato in ingresso al compilatore, che ne controlla innanzitutto la correttezza sintattica (parsificazione). 3.Fase 3. Se ci sono errori, il compilatore genera un file di diagnosi (il.log); altrimenti lo traduce in codice machina: binario (in Unix) o eseguibile (in Windows: un file.exe). Un file.exe si può trasferire da una macchina a un’altra con lo stesso sistema operativo. 2-Elaboratore
Le fasi della programmazione Text editor Parser Traduttore Ok? compilatore sorgente logeseguibile sìno Fase 1 Fase 2 Fase 3 2-Elaboratore
Un ambiente integrato Un ambiente integrato unisce in un unico programma l’editor ed il compilatore (ed altro ancora). Noi usiamo il wxDev-C++: 2-Elaboratore
Quali errori può scoprire il compilatore? Non esiste alcuna procedura automatica ed uniforme che possa decidere se un programma è logicamente corretto, né se una sua esecuzione produrrà un risultato! Alan M. Turing Tuttavia possiamo descrivere formalmente la grammatica di un linguaggio di programmazione e decidere se il testo di un programma rispetta la grammatica data Noam Chomsky 2-Elaboratore
Un circolo vizioso: chi compila il compilatore? I primi compilatori (gli assemblatori) furono scritti in linguaggio macchina! Ogni compilatore, una volta tradotto in un eseguibile, può essere usato per tradurre in un eseguibile il compilatore di un nuovo linguaggio più evoluto. È come se ci fosse una catena umana dai linguaggi più semplici a quelli più evoluti. Assembly C Java 2-Elaboratore Java C Assembly
Interpreti Vale la pena accennare che non tutti linguaggi sono compilati: alcuni si servono di un interprete, ossia di un programma che legge il sorgente riga per riga, ne riconosce le istruzioni ed esegue le azioni corrispondenti. Un programma compilato non ha bisogno del compilatore durante l’esecuzione; un programma interpretato invece ha sempre bisogno dell’interprete. 2-Elaboratore
Architettura del calcolatore e C++ Le nozione centrali di ogni passo del ciclo di calcolo sono: la nozione di indirizzo di memoria e di istruzione di salto. Nella sezione 3 vedremo come una variabile in C++ sia essenzialmente il contenuto di un indirizzo di memoria di una macchina di von Neumann. Una delle nozioni fondamentali del linguaggio C++, forse la più importante, è proprio la nozione di indirizzo di memoria. Nella sezione 4 vedremo, invece, come il C++ evita l’uso delle istruzioni di salto, rimpiazzandole con le istruzioni IF, WHILE, FOR, … 2-Elaboratore
Riepilogo Le parti principali di un calcolatore sono la memoria e la CPU; ciascun calcolatore “comprende” un unico linguaggio macchina; i programmi scritti in C/C++ (o in un altro linguaggio di alto livello) devono essere tradotti in linguaggio macchina da un compilatore; è l’esistenza dei compilatori (e degli interpreti) ciò che rende “poliglotti” i computer (in realta’, ogni computer comprende solo il proprio linguaggio macchina). 2-Elaboratore