Sei sulla pagina 1di 68

Fondamenti di Informatica

(schede riassuntive)

INTRODUZIONE
Scopo: capire come sono fatti i calcolatori e come lavorano. I calcolatori lavorano in codice
binario, questo equivale a dire che nei calcolatori girano solamente segnali elettrici del tipo
0 (equivalente allo stato in cui non passa corrente) e 1 (equivalente allo stato in cui passa
corrente). Ogni calcolatore lavora infatti tra due livelli, corrispondenti ai due stati in cui
ogni singolo componente può trovarsi: 0 e 1, ossia, “non passa corrente” e “passa corrente”.
Transistor: dispositivi in materiale semiconduttore che funzionano come amplificatori dei
segnali elettrici in entrata. Sfruttando questi dispositivi potrei lavorare su 10 livelli diversi,
ma questo non è possibile perché ogni transistor ha delle minime variazioni intrinseche
che in un sistema a 10 livelli di tensione non sono trascurabili. Per questa ragione sfruttare
solo le posizioni estreme è la soluzione migliore, dal momento che i difetti dei transistor
diventano in questo caso trascurabili.
0 e 1 all’interno del calcolatore non hanno un significato intrinsecamente determinato.
Sorge allora il problema di come distinguere le diverse tipologie di dati, se ogni dato
(immagine, suono, parole, numeri, istruzioni, indirizzi, ecc.) vengono espressi come
sequenze di zeri e 1.
La soluzione è proprio nella struttura del calcolatore, che è infatti una macchina sincrona
(cioè legata a un orologio che detta i tempi di funzionamento). Questo significa che:
all’interno del calcolatore è presente un oscillatore che genera un segnale periodico che
prende il nome di clock. Questo segnale, associato ad un’onda quadra, permette di
sincronizzare le attività del calcolatore. Questo vuole dire che il calcolatore saprà se una
certa sequenza di zeri e uni costituisce un dato piuttosto che un’istruzione, in base al
momento in cui questa sequenza binaria gli viene fornita. Questo orologio interno da il
ritmo alle operazioni che il calcolatore deve fare (coordina le attività della macchina).

Nozioni di Base:

- Informatica = significa informazione automatica


- Computer/Elaboratore elettronico = è una macchina concepita per l’elaborazione
automatica di dati (questo implica che non ha il solo scopo di eseguire dei calcoli,
quindi non è una macchina calcolatrice)
- Hardware = consiste di ciò che si può “toccare” e “vedere” del calcolatore, ossia
consiste della parte fisica del calcolatore (componenti circuitali, magnetiche,
meccaniche, ottiche, elettriche, ecc,)
- Software = consiste dell’insieme dei programmi che permettono l’uso effettivo del
calcolatore. Consiste cioè della parte “immateriale” del calcolatore.
- Firmware = componenti hardware pre-programmate, le quali una volta
personalizzate dall’utente non sono più modificabili (esempio: l’ABS viene
programmato per svolgere un certo compito, e non potrà fare cose diverse, anche
da spento deve “ricordarsi” cosa deve fare)
- Input/Output = ingresso/uscita dati verso il sistema hardware e software. I dati
possono essere digitali o analogici (convertiti poi in digitale affinché siano
comprensibili al calcolatore). I dispositivi input/output sono quei dispositivi che
permettono al calcolatore di comunicare con il mondo esterno, ricevendo dati da
elaborare o permettendo di visualizzare dati elaborati.
- Reti = strutture che permettono la comunicazione tra calcolatori, la quale avviene
mediante componenti hardware e software.
- Architettura di un sistema di elaborazione = consiste dell’insieme delle tecniche,
delle soluzioni e delle metodologie che regolano l’interrelazione tra hardware,
software, firmware e l’interfaccia utente.
- Architettura di rete = consiste dell’insieme delle tecniche, delle soluzioni e delle
metodologie che regolano l’interrelazione tra i calcolatori in rete.
Esiste una stratificazione a vari livelli, che permette una maggior astrazione dei
livelli sottostanti, non richiedendo una conoscenza del livello superiore e di quello
inferiore.
Unità di Misura:

- Bit = unità di misura più piccola che descrive due stati diversi (0/1; acceso/spento;
passa corrente/non passa corrente)
- Byte = sequenza di 8 bit
- Kilo byte = 1’024 byte (210)
- Mega byte = 1'048’576 byte (220)
- Giga byte = 230 byte
- Tera byte = 240 byte

Esempi:
1 pagine = 2’000 caratteri = 2KB
1 libro = 500 pagine = 1’000'000 caratteri = 1 MB

- Hertz = unità di misura della frequenza (1 Hz = 1 ciclo al secondo)


- Megahertz … 1 MHz = 1 milione di cicli al secondo
- Mega instructions per second = Mips (milioni di istruzioni al secondo)
- Mega floating point operations per second = Mflops (milioni di operazioni in
“floating point” ossia in virgola mobile, al secondo)
- Baud = misura la velocità di trasmissione dati (bit/sec)

Watch Dog = sistema di temporizzazione hardware (circuito logico) costruito a fianco della
CPU che controlla cosa si modifica nella CPU stessa ad ogni prestabilito intervallo di tempo.
È formato da un contatore che verrà di volta in volta aggiornato ad ogni intervallo di tempo
prestabilito. Se il contenuto del contatore non cambia questo significa che la CPU si è
fermata, allora il Watch dog effettua il reset del sistema permettendo alla CPU di ripartire.

N.B. se raddoppio i periodi di clock non si dimezzano il tempo di elaborazione. Questo


perché l’orologio che detta i tempi di funzionamento della CPU non gestisce le operazioni
ad essa esterne, che hanno tempi diversi (come il colloquio memoria-CPU).

Algoritmo = insieme di operazioni di più passi condotte per risolvere un problema (strada
risolutiva per un problema).
N.B. il consumo di energia è fortemente dipendente dalla frequenza di clock e dalla
tensione operativa, infatti passare dall’uno all’altro valore di tensione consuma energia. Il
motivo per cui la batteria dei computer dura così tanto è perché viene automaticamente
regolata la velocità del clock di sistema. Se il sistema è inattivo la frequenza di clock viene
abbassata assieme alla tensione. Questo permette un risparmio di energia.
Classi di Calcolatori:

- Personal Computer = calcolatori monoutente


- Workstation = con sistema operativo Unix
- Minicomputer = calcolatori usati da decine di utenti contemporaneamente
- Mainframe = calcolatori usati da centinaia di utenti contemporaneamente
- Supercomputer = architetture parallele, dedicati all’elaborazione di grandi quantità
di dati. Presentano dei sistemi operativi particolari.

ARCHITETTURA MACCHINA DI VON NEUMANN

L’architettura di Von Neumann è di fondamentale importanza nello studio dell’informatica.


Sviluppata da Von Neumann negli anni 40 del novecento (circa 1945-6) è ancora oggi
l’architettura hardware su cui è basata la maggior parte dei moderni computer. Questa
architettura ha mantenuto la sua validità anche dopo molti anni perché è un’architettura
che non si lega alla tecnologia. È cioè rimasta valida la sua funzione. Essa è composta da:
- Unità di Input = unità tramite le quali i dati e i programmi vengono inseriti nel
calcolatore per essere elaborati
- Memoria = in cui vengono immagazzinati i dati e i programmi
- CPU = (central processing unit) costituita da un’unità di controllo che supervisiona
ogni attività che prende luogo nel calcolatore; e dall’Unità Logico-Aritmetica (ALU)
che elabora i dati forniti.
- Unità di Output = unità tramite le quali vengono restituiti i risultati all’operatore
- Bus = canale che collega le varie unità tra loro

N.B. Microprocessori: dispositivi elettronici che implementano in un unico circuito


integrato le funzioni di un’intera CPU.
Analizziamo le varie componenti:

1) BUS
Sono i canali di comunicazione tra la CPU e le varie componenti della macchina di
Von Neumann.

Bus Dati = esprime la capacità di elaborazione del processore (ossia quanti bit
possono essere elaborati in parallelo). Sono le linee fisiche di cui la CPU si serve per
leggere i dati da elaborare o per inviare dati alla memoria. Ossia sono le linee fisiche
attraverso le quali avviene il trasferimento di informazioni come sequenza di 0 e 1.

Bus Indirizzi = esprime la capacità di memorizzazione del processore (2m celle di


memoria se m è il numero dei bit del bus). Sono le linee fisiche di cui la CPU si serve
per interloquire con i vari dispositivi (memorie, dispositivi I/O, ecc.). l’informazione
(indirizzo) viene portata a tutte le componenti, mentre a rispondere alla CPU sarà
solo il dispositivo interessato. Questo bus serve cioè a trasportare quelle sequenze
binarie che indicano l’indirizzo della cella di memoria, piuttosto che l’indirizzo di
altre componenti con le quali la CPU vuole interloquire.

Bus Controlli = insieme di collegamenti il cui scopo è coordinare le attività del


sistema. La CPU decide tramite il bus controlli quale componente deve
scrivere/leggere sul bus dati in un certo momento, quale indirizzo leggere sul bus
indirizzi, quali celle di memoria devono scrivere e quali devono leggere, ecc. ne
esistono di vario tipo: Reset, Write, Read, Wait, ecc.
Esempio scrittura dati in memoria

Dato il periodo di clock caratteristico del calcolatore che andiamo a considerare


nell’esempio, analizziamo il caso in cui la CPU voglia scrivere in una cella della
memoria. In accordo con il periodo di clock, in un dato istante la CPU attiverà il bus
degli indirizzi scegliendo il suo interlocutore istantaneo, ossia la CPU invia sul bus
indirizzi l’indirizzo della cella con la quale vuole interloquire. La trasmissione
dell’indirizzo non è istantanea, perché stiamo parlando di linee fisiche (bus).
L’indirizzo viene memorizzato nel MAR, in modo che durante l’operazione di
scrittura non subisca delle variazioni. In un secondo istante, dato dal periodo di
clock, la CPU invierà sul bus dei controlli un segnale per indicare l’operazione che
vuole eseguire sulla cella scelta in precedenza. In questo caso la CPU vuole scrivere
quindi invierà un segnale di WRITE, e per questo sul bus dei controlli sarà attiva la
linea WRITE. A questo punto, dopo un tempo necessario per reperire le
informazioni richieste, in un dato istante la CPU piloterà le linee del bus dati
inviando alla memoria i dati che devono essere memorizzati. Questi vengono
memorizzati temporaneamente nel MBR per evitare che si modifichino durante la
scrittura. A questo punto, una volta terminato il periodo di clock stabilito dal
progettista per la scrittura, il processo termina. A questo punto le linee dei bus non
sono più pilotate dalla CPU e per questo sulle linee dei bus troviamo dei dati
imprecisati. Infatti quando le linee dei bus non sono pilotate, troviamo in esse dei
valori aleatori.
Allo stesso modo per le operazioni di lettura dalla memoria, solo che si attiverà sul
bus dei controlli la linea READ.

Per concedere più tempo alla memoria, necessità che si può presentare se la
memoria non risponde nei tempi stabiliti dal progettista nel recupero in lettura di
un dato, si possono avere due soluzioni:
 Aumento periodi di clock = non efficace perché riduco prestazioni della CPU
 Uso la linea WAIT presente sul bus dei controlli. Questa linea fa sì che la CPU
aspetti a chiudere il trasferimento dei dati prima che tutti i dati non siano stati
recuperati dalla memoria. Così se la memoria risponde in tempi troppo lunghi la
CPU “aspetta” la memoria prima di chiudere il collegamento, cosa che porterebbe
a degli errori se ciò avvenisse prima di aver completato il trasferimento dei dati.

Un’altra linea presente sul bus dei controlli è la linea di INTERRUPT. Quando il
segnale di interrupt viene inviato la CPU interrompe ciò che stava facendo per
dedicarsi alla gestione dell’evento che ha causato l’interrupt.

Un’altra linea del bus dei controlli è la linea di RESET, controllata dal watch dog, e
che se attivata porta al riavvio della CPU, in modo che questa, dopo essersi bloccata,
possa riprendere la propria attività.

Circuito ZERO CROSSING: si tratta di un circuito che attiva e pilota la linea interrupt
del bus controlli per segnalare alla CPU che manca l’alimentazione. Questo problema
è importante. Infatti la RAM è una memoria volatile, quindi è importante che nel
caso di un calo o della totale mancanza di corrente il lavoro della CPU presente in
RAM sia salvato nel disco rigido per non essere perso. Grazie a questo circuito è
possibile avvisare la CPU della mancanza di alimentazione in tempo utile per salvare
il lavoro in corso e non perdere i dati. Questo circuito analizza la corrente in entrata
dall’alimentatore. Quando la corrente è corretta, essa ha la forma di una sinusoide
che periodicamente attraversa lo “0” di tensione siccome è corrente alternata.
Quando la corrente viene a mancare, l’onda non esiste più, quindi non passa più
dallo zero. In questo caso viene allora inviato un segnale di interrupt alla CPU che
ha quindi il tempo per salvare i dati e non perdere il proprio lavoro.

2) MEMORIA
Contenitore a sviluppo monodimensionale di caselle con un loro numero d’ordine,
con cui si interagisce. Può essere costituito da diversi dispositivi, e lo scopo sarà
quello di avere una memoria il più grande possibile, ma senza perdere nella velocità
di risposta (quindi avrò bisogno anche di una memoria auspicabilmente veloce).
Varie tipologie: RAM, ROM, memoria CACHE, ecc.
“MAR” = ossia memory address register, componente della memoria che serve a
mantenere l’indirizzo della cella di memoria cercata in modo da completarne la
ricerca.
“MBR” = ossia memory buffer register, componente della memoria che costituisce il
registro di immagazzinamento della memoria, ossia dove viene temporaneamente
memorizzato il dato che la CPU vuole scrivere in memoria/leggere dalla memoria.

3) COLLOQUIO CPU-PERIFERICHE

Esistono diversi modi per risolvere il problema di ottimizzazione dei tempi della
CPU per quanto riguarda il colloquio con le periferiche.

POLLING
Consiste nel far sì che la CPU interrompa il proprio lavoro periodicamente ad
intervalli regolari per interrogare sequenzialmente le periferiche, provvedendo a
gestire eventuali situazioni in cui l’operazione di I/O sia conclusa e riprenda il
programma interrotto.
 Vantaggi: poco costosa da realizzare
 Svantaggi: la CPU dovendo continuamente interrompere il proprio lavoro rallenta
le altre operazioni in corso ed è sempre impegnata. Perdita di tempo.

TECNICA DEGLI INTERRUPT


Con questa tecnica non è più la CPU ad interrompere sé stessa in maniera
“arbitraria”, ma è la periferica che al momento opportuno (cioè quando ha terminato
l’operazione di I/O) invia un segnale di interrupt alla CPU.
 Vantaggi: la CPU è svincolata dalle continue interruzioni e non deve
continuamente interrompersi per controllare lo stato delle periferiche. Inoltre la
CPU viene avvisata dalla periferica solo quando questa ha terminato il proprio
lavoro ed è pronta a comunicare dati e informazioni necessarie.
 Svantaggi: quando la CPU comunica con una periferica deve adattarsi alla velocità
di questa, producendo così una perdita di tempo relativamente accettabile.
Spreco di tempo perché devo effettuare due trasferimenti dati
(I/OCPUMemoria).

DIRECT MEMORY ACCESS (con controllore di accesso diretto alla memoria)


Modo che si utilizza quando la CPU non è coinvolta come sorgente o destinatario di
dati scambiati nel colloquio con le periferiche. In questo caso la tecnica DMA
permette il passaggio diretto dei dati dalla periferica alla memoria centrale.
 Vantaggi: la CPU è svincolata da processi di comunicazione. Utile se devo ricevere
molti dati velocemente. Opera con segnali di DMA request e DMA aknowledge.
La CPU smette di lavorare (non può usare bus dati) ma ho un solo trasferimento
anziché due, come nella soluzione prima.
 Svantaggi: Collo di bottiglia di Von Neumann. Situazione di estremo sottoutilizzo
del sistema di elaborazione che deve attendere il passaggio dei dati in memoria
prima di avere accesso ai bus dati.
GESTIONE TRAMITE CANALI I/O
Modo che introduce un alto livello di parallelismo è quello con la gestione tramite
Canale Input/output: è un dispositivo associato ad ogni periferica dedicato alla
funzione di scambio di informazioni con le periferiche (accedendo direttamente alla
memoria), svincolando la CPU da operazioni di sincronizzazione, formazione dati,
transcodifica, ecc. (pag. 50).

SINGLE CHIP o MICROCONTROLLORI sono processori in cui tutti i componenti sono


integrati in un unico chip, quindi i bus sono tutti integrati all’interno del chip senza
necessariamente dirigersi verso l’esterno (in questo caso ciò non avviene).
DIGITAL SIGNAL PROCESSOR sono processori che in un solo colpo di clock fanno due
operazioni.

ARCHITETTURA DI UNA CPU

Analizziamo le varie componenti della CPU.


 ALU
ossia Unità Logico-Aritmetica. È quella componente della CPU che ha il compito
di eseguire le operazioni logiche e aritmetiche. Per operare necessità di conoscere
l’’operazione che deve essere eseguita e devono essere noti gli operandi.
 ACCUMULATORE
È un dispositivo collegato alla ALU costituito da un numero finito di celle che
permettono di mantenere temporaneamente gli 0 e gli 1 utili alle operazioni. Può
ricevere i dati dalla memoria per l’ALU o ricevere i dati dall’ALU per la memoria.
Siccome è costituito da un numero finito di celle, sono possibili operazioni
dirette sono su numeri con un massimo numero di cifre definito. Per numeri più
grandi gli operandi verranno spezzati e l’operazione verrà fatta a parti.

 REGISTRO DEI FLAG


Dispositivo associato all’ALU che contiene diversi indicatori utili per segnalare
particolari eventi connessi alle operazioni dell’ALU. (esempio: segnali di riporto,
overflow, prestito, ecc.)

 PROGRAM COUNTER
È un registro la cui funzione è quella di conservare l’indirizzo di memoria della
prossima istruzione che la CPU deve eseguire. È un registro puntatore, cioè che
punta a un dato che si trova in memoria all’indirizzo corrispondente al valore
contenuto nel registro stesso, dicendo a quale cella puntare per eseguire
l’istruzione successiva (contenuta nella cella indicata). Pilota il bus indirizzi.

 INSTRUCTION REGISTER
È un registro interno alla CPU che ha il compito di conservare temporaneamente
il codice operativo ricevuto per evitare che vada perduto con il segnale. Conserva
cioè quella sequenza di zeri e uni che indicano l’operazione da fare in modo che
venga interpretata ed eseguita dalla ALU.

 DECODIFICATORE
Componente della CPU che serve a decodificare la sequenza di 0 e 1 contenuta
nell’IR in modo da comprendere l’istruzione che deve essere eseguita. Cioè legge
i bit del codice operativo e capta l’istruzione da eseguire, il tipo di istruzione, gli
operandi, ecc.

 CONTROLLORE
Detto anche Controller, è un blocco che serve a gestire gli addendi e a comunicare
alla ALU l’operazione da svolgere una volta presenti gli addendi. Cioè ha il
compito di comunicare alla ALU gli addendi che verranno usati nell’operazione
e di comunicare l’operazione da svolgere.

 REGISTRI INTERNI
La memoria RAM è molto grande, ma siccome è esterna alla CPU è necessario del
tempo per consultarla. Questi registri fungono da piccole memorie che “vanno
alla stessa velocità” della CPU. Servono a mantenere temporaneamente diverse
informazioni/dati provenienti dalla memoria o dalla CPU, preservando i dati
dalla dispersione del segnale. Oppure possono avere dei compiti specifici
anziché generici.
 BUS DATI INTERNO / BUS INDIRIZZI INTERNO
Sono le linee di comunicazione tra le varie componenti della CPU per trasferire
dati e indirizzi tra di esse, e verso l’esterno della CPU (Nel colloquio con le
periferiche e le memorie).

 STACK POINTER
Detto anche “puntatore alla pila”, è un registro costituito da una sola cella
associato allo STACK PILA, ed è un dispositivo che punta sempre all’indirizzo
dove si trova in cima della pila.

 STACK
Consiste di una sezione della memoria RAM composta da una serie di
cellette in colonna. Lo Stack segue l’andamento di un programma ogni
volta che esso passa a un sottoprogramma o da quest’ultimo si passa al
programma precedentemente in corso. Esso salva nella sua prima cella
l’indirizzo a cui l’esecuzione del MAIN PROGRAM si è interrotta (ossia il
contenuto del Program Counter). Nella stessa logica nel caso di molteplici
sottoprogrammi nidificati vengono via via segnati gli indirizzi a cui
l’esecuzione dei vari programmi si è interrotta. In questo modo la pila si
sposta in avanti o indietro (se vengono aggiunti o tolti dati). La pila Segue
la logica LIFO (Last In First Out) pertanto la cima della pila contiene
sempre l’ultimo indirizzo utile che sarà presente nello stack pointer.

Spesse volte i dati provenienti dalle periferiche sono nella forma di segnali analogici che
devono così essere convertiti in segnali digitali per essere salvati in memoria.
TRASDUTTORE = converte una grandezza fisica in un segnale analogico

SAMPLE AND HOLD = un dispositivo che serve a mantenere costante la tensione in arrivo
“ad intervalli” così da permettere che il segnale non cambi mentre viene tradotto.

ADC (ANALOGIC DIGITAL CONVERTER) = dispositivo che converte un segnale analogico


variabile in un segnale digitale, assegnando a ogni valore di tensione un segnale digitale.

DSP (DIGITAL SIGNAL PROCESSOR) = dispositivo che elabora i segnali digitali,


comprimendoli e inviandoli in memoria.

DAC (DIGITAL ANALOGIC CONVERTER) =dispositivo che converte un segnale digitale in


un segnale analogico, nelle comunicazioni verso le periferiche.

CICLO MACCHINA

Una volta caricato un programma in memoria, dove le istruzioni vengono salvate, la CPU
lo esegue. Vediamo come avviene l’esecuzione di un programma. Identifichiamo 3 fasi.

 FETCH
Il Program Counter contiene l’indirizzo della prima istruzione che deve essere
eseguita. Allora l’unità di controllo richiede il contenuto dell’indirizzo presente
nel Program Counter. Ossia: attraverso il bus degli indirizzi, pilotato ora dal PC,
l’indirizzo della cella di memoria in cui si trova la prima istruzione da eseguire
va nel MAR. A questo punto identificata la cella di memoria corrispondente a
quell’indirizzo, il “contenuto del contenuto” del MAR (ossia l’istruzione, cioè il
contenuto della cella il cui indirizzo è nel MAR) va nel MBR. In contemporanea a
questo punto il PC viene incrementato in modo da puntare alla cella che contiene
la seconda istruzione da eseguire (conterrà il nuovo indirizzo di questa cella). Da
qui, attraverso il bus dati la prima istruzione arriva alla CPU e viene mandata
nell’Instruction Register.). Inizia così la fase successiva.

 DECODE
Una volta che l’Instruction register ha ricevuto l’istruzione, questa viene
decodificata dal decodificatore che identifica il CODICE OPERATIVO (che
definisce il tipo di istruzione) e il CAMPO OPERANDI, che verrà scomposto nei
due operandi. Inizia così la terza fase.

 EXECUTE
Una volta che l’istruzione è stata decodificata, il controllore attiva i circuiti idonei
a svolgere l’operazione richiesta e fornisce gli operandi perché la svolgano.

N.B. l’operazione di incremento del Program Counter avviene contemporaneamente al


secondo passo della fase di FETCH, questo per un ben chiaro motivo: il tempo utilizzato
per questa operazione è dell’ordine del 10-8 s, che è molto vicino al tempo impiegato nel
primo e nel terzo passo della fase di fetch. Per questo motivo se avvenisse in uno di questi
due momenti, potrebbero verificarsi dei problemi: nel primo passo il PC è impegnato a
fornire l’indirizzo per l’istruzione e non può incrementarsi perché si modificherebbe
l’indirizzo trasmesso. Nel terzo passo ci sarebbe la probabilità (dati i tempi molto vicini)
che il nuovo fetch (vedi pipeline) inizi prima che il PC sia cambiato. Ne conviene che,
siccome il passo 2 occupa più tempo, è meglio effettuare questa operazione proprio in
corrispondenza del secondo passo della fase di fetch.
FORMATO DI UN’ISTRUZIONE
Le istruzioni sono codificate da stringhe di bit. Ogni istruzione presenta un formato
prestabilito:

 CODICE OPERATIVO
Indica quale operazione elementare è richiesta e cioè deve essere eseguita

 CAMPO OPERANDO
Forniscono delle informazioni più dettagliate sull’operazione specificata dal
codice operativo, indicando dove si trovano gli operandi (vengono forniti gli
indirizzi delle celle da cui prelevarli) e dove deve essere poi memorizzato il
risultato.
Una volta nell’IR un’istruzione deve essere decodificata. Bisogna cioè riconoscere:

 Codice Operativo

 Sorgente (dati su cui operare)


 Destinatario (dove porre il risultato)
 Modalità d’Indirizzamento (se sorgente e destinazione sono in memoria)
(gli ultimi tre punti fanno parte del campo operando)

SISTEMI DI NUMERAZIONE
Fin dall’inizio abbiamo detto che l’unico linguaggio comprensibile ai calcolatori è il
linguaggio binario, e abbiamo visto che non è possibile avere linguaggi diversi. Quindi le
uniche cose che un calcolatore sa gestire sono sequenze di 0 e 1. Tuttavia noi siamo abituati
a ragionare nel sistema decimale. Occorre quindi determinare un modo per convertire un
dato numero in base 10, in una qualunque altra base assegnata.

N.B. la rappresentazione è posizionale, ossia ogni cifra in base a dove si trova ha un peso
diverso.
 BINARIO
Sistema di numerazione dotato di due simboli: 0 e 1. Ciascuna cifra in base alla
posizione ha un peso diverso, calcolato come opportuna potenza di due.

Ex. 10110 2 = (1×24) + (0×23) + (1×22) + (1×21) + (0×20) = 32 10

 OTTALE
Sistema di numerazione dotato di otto simboli: 0, 1, 2, 3, 4, 5, 6, 7. Ciascuna cifra in
base alla posizione ha un peso diverso, calcolato come opportuna potenza di otto.

Ex. 3715 8 = (3×83) + (7×82) + (1×81) + (5×80) = 1997 10

 ESADECIMALE
Sistema di numerazione dotato di sedici simboli: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D,
E, F. ciascuna cifra in base alla posizione ha un peso diverso, calcolato come
opportuna potenza di sedici.

Ex. 7CD 16 = (7×162) + (12×161) + (13×160) = 1997 10

Vediamo ora come convertire un numero decimale in una nuova base:


METODO DELLE DIVISIONI
Dato un numero in base 10 (con altre basi non è detto funzioni) divido quel numero per 2.
Otterrò un resto e un quoziente. a questo punto divido il quoziente per due, e continuo
con l’algoritmo sino ad ottenere quoziente uguale a 0. A quel punto leggo i resti della
divisione al contrario e ho ottenuto il numero in codice binario. Questo metodo funziona
anche per il codice ottale (dividerò per 8) e per la base esadecimale (dividerò per 16).

METODO DELLE MOTIPLICAZIONI


Dato un numero frazionario in base 10, per convertirlo in base 2 (discorso analogo per le
altre basi) devo moltiplicare il numero per 2, otterrò una parte intera che sarà 0 o 1 e la
tengo. Se la parte intera è 1, lo tolgo e considero solo il numero dopo la virgola. Continuo
a moltiplicare il risultato precedente per 2 fino a che non ottengo un numero intero. A quel
punto leggo in ordine le parti intere ottenute e ho il numero convertito in binario, ex.
0.10110 2. P.S. numeri decimali non periodici possono dare origine a numeri binari, ottali
o esadecimali periodici!
Ex.
- 0,59375  1.18750 >> 1
- 0,18750  0,37500 >> 0
- 0,37500  0,75000 >> 0
- 0,75000  1,50000 >> 1
- 0,50000  1,00000 >> 1 Stop Risultato = 0,10011 2

CONVERSIONI BINARIO-ESADECIMALE-OTTALE
Le conversioni di un numero tra queste basi sono basate sul fatto che si tratta di basi che
sono legate alle potenze di due. La conversione avviene per raggruppamenti di cifre in
blocchi da 4 se passo da binario a esadecimale e in blocchi da 3 se passo da binario a ottale.
Il viceversa è dato dall’ampliamento di una cifra in esadecimale in 4 cifre binarie, e
l’ampliamento di una cifra ottale in 3 cifre binarie.
Ex: 1F5 16 = 1 | 1111| 0101 2
Ex. 7526 8 = 111| 101 |010 |110 2

RAPPRESENTAZIONE NUMERI BINARI (MODALITA’)


Esistono diverse modalità per rappresentare i numeri decimali in codice binario, modalità
che rispondono ad esigenze diverse e assolvono a scopi diversi all’interno delle operazioni
eseguibili dai calcolatori.
 VALORE ASSOLUTO
Il valore assoluto di un numero si rappresenta a meno del segno tenendo conto del
modo sopra utilizzato per convertire numeri decimali in binario.

 MODULO E SEGNO
Il primo bit rappresenta il segno e gli altri rappresentano il modulo del numero. Ex,
con 8 bit non rappresenterei i numeri da 0 a 255, ma in modulo e segno rappresento
i numeri da -127 a +127 (cioè da -27-1 a 27-1) e ho due rappresentazioni per lo 0,
una positiva e una negativa.
1  “MENO”
0  “PIU’”

N.B. poco usato a causa della difficoltà nel fare i calcoli

 COMPLEMENTO ALLA BASE DI UN NUMERO


𝐵𝑛
Data la base B e n numero delle cifre (bit) le combinazioni da 0 a −1
2
𝐵𝑛
rappresentano i numeri positivi, le combinazioni da a Bn-1 rappresentano i numeri
2
negativi, secondo questa regola: sia X un numero positivo, allora -X si rappresenta
come quel numero che manca a X per arrivare a Bn.
Regola pratica  se ho un numero positivo, l’equivalente negativo si trova
riscrivendo da destra tutti gli zeri sino alla prima cifra significativa inclusa, poi si fa
il complemento alla base delle altre cifre.

Ex. Complemento a 10 … X=360  -X= 640

 COMPLEMENTO A 2
Come per il caso generale, ho date n cifre, due intervalli.
2𝑛 2𝑛
Le combinazioni da 0 a 2
− 1 rappresentano i numeri positivi, le combinazioni da 2
a 2n-1 rappresentano i numeri negativi.
Regola Pratica  se X è un numero positivo, il suo corrispondente negativo si ottiene
scrivendo da destra tutti gli 0 di X sino alla prima cifra significativa inclusa, e poi si
scambiano 0 e 1. Procedimento valido anche all’inverso.
N.B. il bit più significativo è il bit di segno (1  meno; 0  più) che nei negativi
viene calcolato!

2𝑛
Massimo numero rappresentabile  2
− 1
2 𝑛
Minimo numero rappresentabile  −2
Rappresentazioni per lo zero  UNA (tutti zeri)

 COMPLEMENTO ALLA BASE -1


𝐵𝑛
Diamo il caso generale. Divido l’intervallo in due parti. Le combinazioni da 0 a 2
−1
𝐵𝑛
rappresentano numeri positivi, mentre le combinazioni da 2
a Bn-1 rappresentano i
numeri negativi. Secondo questa regola: se X è un numero positivo, il suo
corrispettivo negativo, -X, è quel numero che manca a X per arrivare a Bn-1.
Regola pratica  Se X è un numero positivo, l’equivalente negativo si ottiene
scambiando gli 0 con gli 1 e viceversa (“complementando”). Procedimento valido
anche al contrario.

N.B. il complemento alla base si può ottenere sommando 1 al complemento alla base
-1.

 COMPLEMENTO A 1
Come nel caso generale, date n cifre, ho suddiviso l’insieme in due intervalli. Le
2𝑛
combinazioni da 0 a 2
− 1 rappresentano i numeri positivi, mentre le combinazioni
2𝑛
da 2
a 2n-1 rappresentano i numeri negativi. È sempre presente il bit del segno che
è 0 per i positivi e 1 per i negativi, e viene calcolato.
Regola Pratica  se X è un numero positivo, il suo corrispondente negativo si ottiene
scambiando gli 0 con gli 1 e viceversa (“complementando”). Procedimento valido
anche all’inverso.

2𝑛
Massimo numero rappresentabile  2
−1
2 𝑛
Minimo numero rappresentabile  − 2 +1
Rappresentazioni per lo zero  DUE (tutti zeri/tutti uni)
N.B. con la tecnica del complemento si può utilizzare un solo circuito per le operazioni
di somma e sottrazione senza dover operare una serie di confronti tra gli operandi, da qui
l’utilità di queste due tecniche di rappresentazione. (Vantaggio)
 NOTAZIONE IN ECCESSO (POLARIZZATA)
Usata per scopi particolari, alla rappresentazione in decimale di un numero (con il
proprio segno!) sommo una costante, detta costante di polarizzazione (fissato il
numero di bit n), che corrisponde al numero di spostamenti necessari per avere una
rappresentazione ordinata dal numero negativo più basso al numero negativo più
alto, invece che una rappresentazione spezzata come nel complemento a 2.
Costante di Polarizzazione  2𝑛−1 (talvolta anche 2𝑛−1 − 1)
N.B. in questa notazione i segni sono invertiti (1  più; 0  meno); massimi e
minimi rappresentabili come nel complemento a 2.

Ex. +6 rappresentato in eccesso con 4 bit.


6+8=14 14 10  1110 2 cioè + 6 10 = 1110 2 (eccesso 8)

Ex. -4 rappresentato in eccesso con 4 bit.


-4+8=4 4 10  0100 2 cioè -4 10 = 0100 2 (eccesso 8)

Ex. 1011 in eccesso 8 che numero rappresenta?


1011 2 = 11 10 11-8 = +3 cioè 1011 2 = +3 10 (eccesso 8)

Ex. 0110 in eccesso a 8 che numero rappresenta?


0110 2 = 6 10 6-8 = -2 cioè 0110 2 = -2 10 (eccesso 8)

Ex. 1101 in complemento a 2, che numero rappresenta in eccesso 8?


1101 2 = -3 in complemento a 2 (13-16=-3)
1101 2 = +5 in eccesso a 8 (13-8=+5)

 NOTAZIONE IN VIRGOLA FISSA


Notazione utilizzata per la rappresentazione di numeri razionali. Secondo questo
metodo, dato n numero di bit da usare per la rappresentazione del numero
razionale, stabilisco a priori la posizione della virgola e decido quanti bit attribuire
alla parte intera e quanti bit attribuire alla parte decimale. Per i numeri negati si può
utilizzare la tecnica del complemento alla base (cioè 2 in binario).
Problema = ridotto intervallo di rappresentazione dei numeri e ridotta precisione di
rappresentazione.

Ex. Rappresentare con 12 bit (8 per parte intera e 4 per parte decimale) 72,6

72:2=36 >> 0
36:2=18 >> 0
18:2=9 >> 0
9:2=4 >> 1  72 = 01001000 (ho aggiunto a sx uno 0 per avere 8 bit richiesti)
4:2=2 >> 0
2:2=1 >> 0
1:2=0 >> 1 stop!

0,6*2=1,2 >> 1 0,4*2=0,8 >> 0  0,6 = 1001


0,2*2=0,4 >> 0 0,8*2=1,6 >> 1
Quindi ho che 72,6 10 = 01001000 1001 2

Ex. Rappresentare come sopra -72,6

72,6 = 01001000 1001  -72,6 10 = 10110111 0111 2 (complemento a 2)

 NOTAZIONE IN VIRGOLA MOBILE (FLOATING POINT)


Detta anche “rappresentazione normalizzata” e meglio nota come rappresentazione
SEM, è un metodo valido ed efficacie di rappresentazione dei numeri, che permette
la rappresentazione di numeri anche molto grandi con pochissimi bit a disposizione.
Ogni numero scritto in virgola mobile è costituito da tre parti:

1) SEGNO (S)
1  negativo
0  positivo

2) MANTISSA (M)
Cifre significative del numero rappresentate in forma normalizzata, ossia nella
forma 0,1………… (con la prima cifra significativa dopo la virgola)

3) ESPONENTE (E)
Esponente a cui bisogna elevare la base perché mi dia il numero di partenza. Esso
è scritto in notazione polarizzata o in complemento alla base, nel nostro caso 2).

Per la rappresentazione è necessario fissare quanti bit dedicare a ciascuna delle tre
parti, normalizzare la mantissa, aggiustando opportunamente l’esponente, e
disporre le tre parti secondo la convenzione: S + E + M.
 Singola Precisione  32 bit [ 1 – 8 – 23 ]
 Doppia Precisione  64 bit [ 1 – 11 – 52 ]
Si parla di DINAMICA per descrivere l’intervallo di numeri rappresentabili in floating
point. Lo vediamo nei due casi sopra (considero E in complemento).
1) In Singola precisione l’esponente più grande è +127, e il più piccolo è-128. Quindi
siccome la mantissa tende a 1 al massimo, ho che N, numero rappresentato:
−2127 < N < 2127
−1038 < N < 1038

Numero più piccolo in modulo è 0,1×2−128 (N.B. non è il numero con la mantissa
più piccola!)

2) In Doppia Precisione l’esponente più grande in complemento è 1023, Quindi


siccome la mantissa tende a 1 al massimo, ho che N, numero rappresentato:
−21023 < N < 21023

Numero più piccolo in modulo è 0,1×2−1024 (N.B. non è il numero con la mantissa
più piccola!)
PROBLEMI:

OVERFLOW = situazione che si verifica quando il numero che si vuole rappresentare


ha mantissa superiore alla massima mantissa rappresentabile e
contemporaneamente l’esponente è maggiore del massimo esponente
rappresentabile. Cioè si verifica per valori superiori al massimo numero positivo
rappresentabile o inferiori al minimo numero rappresentabile.
Cioè quando: N > 2127 oppure N < -2127
UNDERFLOW = situazione che si verifica quando il numero che si vuole
rappresentare (negativo) ha mantissa più piccola della minima mantissa
rappresentabile ed esponente più piccolo del minimo esponente rappresentabile. Si
verifica per valori superiori al massimo numero negativo rappresentabile, o
inferiori al minimo numero positivo rappresentabile.
Cioè quando: -0,1*2^-128 < N < 0,1*2-128

 STANDAD IEEE 754


Sistema di rappresentazione in virgola mobile che prevede però una particolarità.
Anziché avere 0,M avremo 1,M. questo significa che la prima cifra significativa (che
sarà un 1) viene sottointesa, e quindi posta prima della virgola. Questo mi permette
di avere una maggior precisione a livello della mantissa, è però necessario conoscere
in che notazione sto lavorando! L’1 tolto però deve essere considerato nella
conversione. Per convenzione 0 è il numero che rappresenta M=0 (tutti zeri).
L’esponente è scritto in notazione per eccesso.

Ex. 0,1  1,0*2-1  0 01111111 00000000000000000000000


In floating point…
0,1 = 0,1*20  0 00000000 10000000000000000000000
 CODIFICA BCD
Ogni cifra decimale viene codificata con 4 bit (Binary-Coded decimal)

Ex. 123  0001 0010 0011


Ex. -145  non rappresentabile (non esistono codifiche per il segno in BCD)

 CODICE AD ECCESSO 3
È la codifica di un numero fornito che si ottiene esprimendo ogni cifra in codice BCD
dopo averci sommato 3.
Ex. 123  (1+3) (2+3) (3+3)  0100 0101 0110

 CODICE 2421
Codice di rappresentazione dei numeri, che prevede che ogni numero sia
rappresentato come in BCD, solo che il peso assegnato a ogni bit è diverso, ed è
espresso proprio dal nome del codice [ 2, 4, 2, 1 ].

Ex. 123  0001 0010 0011


Ex. 936  1111 0011 1100 (perché 0110 non è utilizzata)

Per questo codice occorre avere presente la tabella di riferimento, perché ci sono
diverse configurazioni inutilizzate delle 16 a disposizione.

 CODICE GRAY
Detto anche “Codice riflesso” viene costruito mediante un algoritmo ricorsivo. Serve
a codificare un numero in modo che le stringhe di bit che rappresentano numeri
consecutivi differiscano di un solo bit, eliminando il problema di transizioni non
valide da una codifica alla successiva.
Per numeri molto grandi tuttavia può essere oneroso e complicato costruire dato un
numero binario l’equivalente in codifica Gray, pertanto si usa la definizione:
partendo dal bit più significativo questo rimane inalterato e viene così riportato; i
bit successivi si ottengono (da sx. a dx.) facendo un’operazione di EXOR tra la cifra
considerata e la precedente, il risultato sarà la nuova cifra.

Ex. 11000010 diventa:

1 cifra invariata
1 exor 1 = 0
0 exor 1 = 1
… ottengo così il numero in codice Gray= 10100011
OPERAZIONI TRA NUMERI BINARI (E CASI PARTICOLARI)

Nelle operazioni tra numeri binari si segue questo schema:

1) SOMMA
3) PRODOTTO
1+ 1 = 0 riporto 1
1+ 0 =1 1 × 1 =1
0+ 1 =0 1 × 0 =0
0+ 0 =0 0 × 1 =0
0 × 0 =0
2) SOTTRAZIONE
4) QUOZIENTE
1 –1 = 0 Si effettua come la divisione tra
1 –0 = 1 polinomi (simile metodo, non
0 –1 = 1 prestito 1 uguale!)
0 –0 = 0

Nelle operazioni tra numeri binari è di grande utilità l’utilizzo della


rappresentazione in complemento a 2 (alla base), utilizzando un solo circuito per
effettuare la somma e la sottrazione (date n cifre):
dati A e B due numeri binari =
A – B = A + (2n – B) trascurando il riporto
Cioè A – B = A + (-B in complemento a 2)

Se sono in complemento a 1 (complemento alla base -1) devo sommare il riporto al


risultato. Cioè:
A – B = A + (2n – 1 + B) +1
Cioè A – B = A + (-B in complemento a 1) +1

CIRCUITO DI SOMMA/SOTTRAZIONE
Circuito che effettua le operazioni di somma e sottrazione (sfruttando le proprietà
della rappresentazione in complemento). Dati degli input, produce un risultato e un
riporto.

a, b, Ri = entrate
Ro = riporto
C = risultato

Ora un esempio di sommatore per numeri binari a 3 bit C = A + B


Estendiamo il concetto di OVERFLOW = superamento della capacità di
rappresentazione dei numeri in complemento a due. Indica il risultato di una
somma algebrica non rappresentabile con il numero di bit a disposizione.

Estendiamo anche il concetto di RIPORTO = numero che rimane quando supero la


capacità di rappresentazione dei numeri in valore assoluto.

Quando si ottiene un OVERFLOW?


1) Quando sommando due numeri positivi ottengo un numero negativo
2) Quando sommando due numeri negativi ottengo un numero positivo

In entrambi i casi i numeri non sono rappresentabili in N bit, ma lo sono


sicuramente in N+1 bit.

OPERAZIONI TRA NUMERI IN VIRGOLA MOBILE


Analizziamo questo caso particolare di operazioni tra numeri binari in virgola
mobile.

 Moltiplicazione e Divisione
1) Le mantisse di moltiplicano o dividono
2) Gli esponenti si sommano o sottraggono
3) Se necessario si rinormalizza la mantissa e si corregge l’esponente

 Somma e Sottrazione
1) L’esponente più piccolo viene reso uguale al più grande spostando la
mantissa verso destra del numero di cifre pari alla differenza tra gli
esponenti.
2) Le mantisse vengono sommate o sottratte
3) La mantissa del risultato viene normalizzata e l’esponente corretto

N.B. alcune cifre poco significative della mantissa nei calcoli potrebbero
andare perse, proprio a seguito del numero massimo di bit che sono dedicati
alla mantissa.

Errori di Troncamento = errore dato dal fatto che la mantissa è costituita da un


numero finito di bit, questo fa sì che stringhe di bit più lunghe debbano essere
troncate, perdendo così delle informazioni sul numero rappresentato.
CODIFICA DI DATI NON NUMERICI

In un calcolatore tutto è basato sui numeri, e tutto segue la logica e l’aritmetica binaria. Il
calcolatore, per essere utile all’uomo, deve essere anche in grado però di trattare dati non
numerici, ossia deve essere in grado di trattare altri simboli. Per questo sono stati creati
dei CODICI, ossia degli strumenti che associano a ogni simbolo di un alfabeto più ricco di
simboli, un simbolo, o una sequenza di simboli di un alfabeto più ridotto. La CODIFICA è
la corrispondenza biunivoca tra gli elementi di un alfabeto e un sottoinsieme di stringhe
di un alfabeto più ridotto. (La codifica consiste cioè di regole di corrispondenza tra
alfabeti).

DISTANZA DI HAMMING = è il numero minimo di bit di cui differiscono due parole


qualsiasi del codice in considerazione. Indicata con H. Ci permette di distinguere tra due
tipologie di codici, ridondanti e non-ridondanti. Un codice può essere reso ridondante,
facendogli assumere la funzione di rilevare errori e eventualmente di correggerli.

CODICI RIDONDANTI = codici con distanza di Hamming superiore a 1 (H > 1). Sono cioè
codici che in cui viene usato un numero di bit superiore al minimo necessario per codificare
tutti i simboli del codice (ci saranno così diverse configurazioni inutilizzate).

CODICI NON RIDONDANTI = codici con distanza di Hamming uguale a 1 (H = 1). Sono cioè
codici in cui viene usato il minimo numero di bit necessari per codificare tutti i simboli del
codice/alfabeto.
Dato l’alfabeto R, se C è la sua cardinalità, qual è il numero minimo di bit necessari per
rappresentare gli elementi dell’insieme?
2n ≥ C
n ≥ ⌈log 2 (𝐶)⌋ = M

(dove i due simboli indicano il contenuto arrotondato per eccesso)


Ex. Se avessi 100 simboli e uso 8 bit ho 128 configurazioni, ma non è ridondanza, perché
se usassi 7 bit avrei 64 configurazioni, e non bastano. Se usassi 9 bit invece sarebbe una
ridondanza.
La ridondanza può essere utile per ovviare o limitare la possibilità di errore.
 CODICI RIDONDANTI A RILEVAZIONE DI ERRORI
Codici con H > 1, ne troviamo di due tipologie diffuse

1) BIT DI PARITA’
Codice con H = 2, in cui tutte le stringhe di bit presentano un bit aggiuntivo,
detto bit di parità, assegnato in modo che nella stringa sia presente un numero
dispari di 1. Se dopo la trasmissione si rivela che una stringa contiene un numero
pari di 1 allora possiamo dire che si presentato un errore. Posso per codici
generici rilevare R errori per stringa, con R=H-1. Qui posso rivelarne solo 1.

2) BIT DI DISPARITA’
Codice con H = 2 costruito come il primo, ma in modo da avere, grazie al bit
aggiuntivo, un numero pari di 1. Quindi l’errore (sempre 1) sarà rivelato laddove
si avranno stringhe con un numero pari di 1.
3) BYTE DI CONTROLLO
Funziona come i precedenti, solo che vengono aggiunti 8 bit, ciascuno dei quali
funziona da bit di parità/disparità associato ad alcuni bit della stringa, per un
controllo più approfondito per evitare un problema comune.

Problema = se a cambiare sono due bit, con i primi due metodi potrei non
accorgermene, mentre ho più probabilità di individuarli con il terzo metodo.
4) CRC (CODICE CICLICO)
Metodo analogo a quello del byte di controllo, e al metodo delle SOMME DI
CONTROLLO. Il metodo CRC prevede che l’insieme dei dati da inviare (M) sia
trattato come un polinomio di grado k-1 (k = bit della stringa), i cui coefficienti
sono proprio i bit del messaggio. Mediante un secondo polinomio di grado (G) si
arriva a un terzo polinomio T, divisibile per G. T sarà il polinomio che verrà
inviato. In ricezione il polinomio T viene diviso per G (noto al destinatario e al
mittente) e se la divisione da resto 0 vuol dire che il messaggio è intatto,
altrimenti deve essere rinviato. In altri casi insieme ai dati viene inviato un
numero molto grande divisibile per un numero noto al mittente e al destinatario,
con resto 0. (usato per comunicazioni a grandissima distanza). Se alla ricezione,
a divisione fatta, il resto è zero, il contenuto dei dati è probabilmente intatto, se
invece ho resto diverso da 0 vuol dire che il numero è cambiato e i dati possono
essere stati modificati (oggetto di errore).

 CODICI RIDONDANTI A CORREZIONE DI ERRORI


Sono Codici, detti anche Codici di Hamming, che presentano H > 2. Codici con
capacità di autocorrezione. Il più noto ha H=3. Sono codici che permettono di
𝐻−1
rilevare R= H – C – 1 errori e di poterne correggere 2 ≥ C. operativamente quello
che si fa è vedere, data una lista che mostra la codifica di una serie di dati, quale
dato ha una distanza di Hamming pari a 1 rispetto la sequenza ricevuta, questo mi
permetterà di correggere l’errore, mentre posso comunque evidenziare la presenza
di almeno 2 errori in altri pattern di bit. Esempio a pag. 77 del libro.
Affinché possa essere corretto un errore, bisogna inserire in una stringa di n bit, k
bit di controllo secondo la relazione
n ≤ 2k – k – 1
funziona bene se errori sono distribuiti casualmente e rivela e corregge un solo bit.
INFORMAZIONI ALFANUMERICHE
Si definisce ALFABETO ESTERNO di un calcolatore l’insieme dei caratteri che è in gradi di
leggere e stampare mediante le unità di input e output. È un alfabeto di almeno 64 caratteri
(26 lettere dell’alfabeto inglese/10 cifre numeriche/28 simboli vari).
 EBCDIC
Rappresenta caratteri alfanumerici e speciali, 8 bit, personalizzato per le varie
nazionalità (obsoleto)

 UNICODE
Rappresenta tutti i caratteri della lingua parlata dall’uomo, 16 bit. (usato da Java,
HP, IBM, Microsoft,)
 ASCII
Che sta per American Standard Code for Information Interchange. Ne esistono due
versioni:
 7 bit  128 simboli (ottavo bit usato a volte per ridondanza e come bit di
parità)
 8 bit  256 simboli (ASCII esteso) codifica anche lettere accentate e caratteri
grafici, ma la codifica non è standardizzata, cioè a una data sequenza
possono corrispondere simboli diversi.
Codice più usato per la codifica alfanumerica.

INFORMAZIONI GRAFICHE (CODIFICA IMMAGINI)


In un calcolatore tutto è discreto, ma quando parliamo di immagini parliamo di luce, e cioè
siamo nel “continuo”. Un calcolatore nel momento in cui acquisisce un’immagine la
scompone in sequenze di elementi codificati con sequenze binarie. Ho varie tipologie:

 BITMAP
Come dice il termine, considera l’immagine come una matrice di punti detti PIXEL.
Ogni pixel è codificato da una sequenza di bit. Maggiore è il numero di pixel,
maggiore sarà la qualità dell’immagine (che dipende anche dal numero di bit per
pixel). Solitamente si codifica a 8 bit per il bianco, il nero e le sfumature di grigio.
Per le immagini a colori bisogna accostare a ogni pixel tre codifiche da 8 bit, una per
ogni colore primario (RGB, red, green, blue), e delle codifiche aggiuntive per regolare
i parametri di intensità dei tre colori. Profondità di colore =numero di bit per
codificare un pixel. Sintesi additiva/sottrattiva.
Problemi = le immagini bitmap occupano molto spazio, e sono poco adattabili ad
essere ridimensionate, perché non è possibile cambiare la grandezza dei pixel.
Formati:
 TIFF (24 bit per pixel)
 GIF (memorizzare più immagini in un file)
 JFIF (codifica JPEG, immagine composta per righe alterne, “visualizzazione
interallacciata”)
 BMT (usata da Windows, a 1,4,8 e 24 bit)

 IMMAGINI VETTORIALI
Formato applicato nell’ambito della progettazione (meccanica, elettronica, ecc.).
l’immagine viene costruita con elementi di alto livello (linee, forme geometriche,
ecc.). Decodificano le immagini in base a formule matematiche (mediante un
identificatore e alcuni parametri).
Vantaggi = indipendenza dal dispositivo di visualizzazione e dalla sua risoluzione
grafica; ogni elemento grafico è indipendente dall’altro e sono modificabili
separatamente; occupano poco spazio in memoria (intuibile).
Svantaggi = non sono applicabili a tutte le immagini (come a immagini naturali), e
sono manipolabili solo dal software che le ha create o software compatibili.
Formati
 PostScript (incorporato nelle stampanti, da cui derivano EPS e PDF)
 DXF (usato da programmi di disegno, memorizza i vettori come testo.)

 IMMAGINI IN MOVIMENTO
Rappresentate come sequenze di immagini fisse (frame) visualizzate a una
frequenza sufficientemente alta da consentire di percepirle come in movimento.
Standard è MPEG (ogni frame ha codifica JPEG). Usate varie tecniche di
compressione.

ALGEBRA BOOLENA

Algebra definita da due elementi: VERO o FALSO, associabili a 1 e 0. Introduciamo


un po’ di notazione:

::= significa “è definito/composto da”


| significa “oppure”

Introduciamo ora gli operatori dell’algebra booleana.


 NOT
Indica la negazione del segnale in ingresso, simbolo “ “
Quindi:
1=0
0=1

 AND
Indica il prodotto logico dei segnali in ingresso, simbolo “ * “
Quindi:
1*1=1
1*0=0
0*1=0
0*0=0
 OR
Indica la somma logica dei segnali in ingresso, simbolo “ + “
Quindi:
1+1=1
1+0=1
0+1=1
0+0=0
 NAND
Operatore universale, perché insieme a NOR può rappresentare i tre operatori
fondamentali, negazione dell’AND, simbolo “ / “
Quindi:
1/1=0
1/0=1
0/1=1
0/0=1
 NOR
Operatore universale, perché insieme a NAND può rappresentare i tre operatori
fondamentali, negazione dell’OR, simbolo “↓“
Quindi:
1 ↓ 1 = 0
1 ↓ 0 = 0
0 ↓ 1 = 0
0 ↓ 0 = 1

 EXOR
Operatore OR-Esclusivo, detto “somma modulo 2” restituisce 1 solo se il numero di
operandi uguali a 1 è dispari, altrimenti 0; simbolo “ ⊕ “
Quindi:
1⊕1=0
1⊕0=1
0⊕1=1
0⊕0=0

Sulle variabili booleane può essere definita una funzione booleana (logica) che assegna a
ogni valore delle entrate il valore di uscita 0 o 1. Costruisco così una tavola di verità, utile
per vedere che valore assume la funzione in corrispondenza delle varie entrate (tabella).
Con n variabili avrò 2n righe.

PROPRIETA’ DELL’ALGEBRA BOOLEANA (TRE OPERATORI FONDAMENTALI)


Teorema di dualità = Ogni identità e ogni proprietà resta valida se si scambiano tra loro
gli operatori AND, OR, e gli zeri con gli uni. L’espressione ottenuta si dice duale a quella
di partenza.

x*0=0 x+1=1
x*1=x x+0=x
x*x=x x+x=x idempotenza
x*𝑥=0 x+𝑥=1 complementazione

x*y=y*x x+y=y+x p. commutativa


(x * y) * z = x * (z * y) (x + y) + z = x + (y + z) p. associativa

x * (y + z) = (x * y) + (x * z) x + (y * z) = (x + y) * (y + z) p. distributiva
x + (x * y) = x x * (x + y ) = x
x * ( 𝑥 + y) = x * y x + ( 𝑥 * y) = (x + y) p. assorbimento

De Morgan : 𝑥∗𝑦 = 𝑥+ 𝑦 𝑥+𝑦 = 𝑥∗ 𝑦 𝑥 =𝑥


PROPRIETA’ DEGLI OPERATORI UNIVERSALI

Vale il teorema di dualità anche per gli operatori universali.


x ↓1 = 0 x/0=1

x ↓0 = 1 x/1=0

x ↓ (y ↓ z) ≠ (x ↓ y) ↓ z x / (y / z) ≠ (x / y) / z
x↓x=𝑥 x/x=𝑥

𝑥 ↓𝑦 =𝑥∗𝑦 𝑥/𝑦=x+y

𝑥 ↓𝑦 =𝑥+𝑦 𝑥/𝑦 = 𝑥 ∗ 𝑦

Occorre ora fornire una dimostrazione del perché possiamo denominare NAND e NOR
operatori universali. Determiniamo cioè come ottenere AND, OR e NOT a partire da porte
logiche NAND e poi da porte logiche NOR.

USIAMO SOLO “ NAND”

x x y x y
 AND 𝑥 ∗ 𝑦 ∗ 1 = 𝑥 ∗ 𝑦 + 1 = (𝑥 ∗ 𝑦) + 0 = 𝑥 ∗ 𝑦 y

x x

 OR 𝑥∗ 𝑦 = 𝑥+ 𝑦 =𝑥+𝑦 x y
y y

x x
 NOT 𝑥∗𝑥 = 𝑥 𝑎𝑛𝑎𝑙𝑜𝑔𝑎𝑚𝑒𝑛𝑡𝑒 𝑥∗1= 𝑥

(la negazione della operazione AND “ * “ sta per NAND)

USIAMO SOLO “NOR”


x x

x y
 AND 𝑥+ 𝑦 = 𝑥+ 𝑦 =𝑥+𝑦
y y
 OR 𝑥 + 𝑦 + 0 = 𝑥 + 𝑦 ∗ 0 = (𝑥 + 𝑦) ∗ 1 = 𝑥 + 𝑦 x x y x y
y

x x
 NOT 𝑥+0= 𝑥 𝑎𝑛𝑎𝑙𝑜𝑔𝑎𝑚𝑒𝑛𝑡𝑒 𝑥+𝑥 = 𝑥

(la negazione della operazione OR “ + “ sta per NOR)

RICAVIAMO EXOR E PROPRIETA’ D’USO


 EXOR 𝑓(𝑥, 𝑦) = (𝑥 ∗ 𝑦) + (𝑥 ∗ 𝑦) = 𝑥 ⊕ 𝑦

x⊕0=x x⊕y=y⊕x p. commutativa


x⊕1=𝑥 (𝑥 ⊕ 𝑦) ⊕ 𝑧 = 𝑥 ⊕ (𝑦 ⊕ 𝑧) p. associativa

x⊕x=0 .

x⊕ 𝑥=1 L’exor viene usato per azzerare l’accumulatore della CPU

l’exor viene anche usato nella ALU per le operazioni di somma in complemento a 2, usato
come convertitore automatico per trovare il complemento di un numero. In ogni caso
vedremo meglio il suo utilizzo quando parleremo delle operazioni.

ISTRUZIONI (LINGUAGGIO MACCHINA)


Una CPU per poter lavorare deve conoscere una serie di istruzioni elementari
(essenziali)che una volta decodificate, le permetteranno di ottenere il risultato richiesto. Le
istruzioni sono scritte in ASSEMBLY LANGUAGE, ovvero una rappresentazione simbolica
che usa codici mnemonici per indicare le varie operazioni da eseguire. ASSEMBLATORE =
programma che traduce i codici in Assembly Language in istruzioni scritte in linguaggio
macchina (ossia in forma binaria). Esistono vari tipi di istruzioni:
 TRASFERIMENTO DATI
Istruzioni che servono a trasferire dati dalla memoria ai registri, da registri a registri,
da registri a unità esterne, e viceversa. Ossia si occupano del trasferimento dei dati.
Siano A e B dei registri:
 LOAD (memoria)  CPU
 STORE CPU  (memoria)

Ex.
LDA<indirizzo> cioè (indirizzo)  A
STB<indirizzo> cioè (B)  INDIRIZZO
MOV A B cioè (A)  B
INP<PORTA>B cioè (PORTA)  B (coinvolge le periferiche)
OUT A<PORTA> cioè (A)  PORTA (coinvolge le periferiche)

Le ultime due sono proprio le istruzioni di Input/Output (I/O)


 ISTRUZIONI ARITMETICHE
Permettono di eseguire operazioni aritmetiche elementari su numeri interi.
Chiedono alla CPU di svolgere i compiti propri dell’ALU. Siano A e B due registri e
Cy il valore del flag di riporto o prestito:
 ADD somma
 SUB sottrazione

Ex.
ADD<indirizzo>A cioè (indirizzo) + (A)  A
ADC<indirizzo>A cioè (indirizzo) + (Cy) + (A)  A
SUB A<indirizzo> cioè (indirizzo) – (A)  A
SBC B<indirizzo> cioè (indirizzo) – (B) – (Cy)  A

Indicatori Flag che possono essere presenti:

o CARRY (C) = c’è stato o meno un riporto


o OVERFLOW (W) = c’è stato o meno un overflow (complemento a 2)
o ZERO (Z) = il risultato è o no zero
o NEGATIVE (N) = il risultato è o no negativo

 ISTRUZIONI LOGICHE
Permettono di eseguire operazioni logiche su stringhe di bit. (considero A e B i
registri che contengono i dati su cui eseguire le operazioni). I vari operatori operano
su coppie di bit.
 AND
 OR
 NOT
 EXOR (XOR)
Ex.
o AND <indirizzo>A cioè (indirizzo) * (A)  A
o OR <indirizzo >B cioè (indirizzo) + (B)  B
o EXOR <indirizzo>A cioè (indirizzo) ⊕ (A)  A
o NOT B cioè ( 𝐵 )  A

Questi operatori vengono usati anche per svolgere operazioni aritmetiche più in
fretta. Come segue al prossimo gruppo, che sarebbe meglio definire un sottogruppo
delle operazioni logiche e aritmetiche.

 ISTRUZIONI DI ROTATE E SHIFT


Sono istruzioni che operano sul contenuto di un registro. Esse servono a operare un
singolo bit di una fila di celle, senza cambiare il contenuto delle altre. Le istruzioni
sono:

 SHIFT LOGICO A DESTRA


Utilizzato per le stringhe di bit in valore assoluto. Consiste nello spostamento
a destra delle cifre di un numero, inserendo uno zero nelle posizioni lasciate
libere (in base al numero di posizioni di cui bisogna spostare). Il resto viene
messo nel CARRY. Corrisponde a una divisione per potenze di 2.

 SHIFT ARITMETICO A DESTRA


Viene utilizzato per le stringhe in complemento a due; il bit più significativo
viene traslato e riconfermato nella propria cella, mentre gli altri bit si
spostano a destra di una posizione. Corrisponde a una divisione per potenze
di 2. Il resto va nel CARRY.
N.B. metodo usato per la divisione per potenze di due senza commettere
overflow, siccome il bit del segno viene riconfermato nella prima cella.

 SHIFT LOGICO A SINISTRA


Utilizzato per le stringhe di bit in valore assoluto. Consiste nello
spostamento a sinistra delle cifre di un numero, inserendo uno zero nelle
posizioni lasciate libere a destra (tanti quante sono le posizioni di cui
bisogna spostarsi). Il riporto viene messo nel CARRY. Corrisponde a una
moltiplicazione per potenze di 2.

 SHIFT ARITMETICO A SINISTRA


Analogo a quello logico per struttura e scopi, ma utilizzabili solo per i numeri
in complemento a 2. Si usa se e solo se nello spostamento richiesto il bit
del segno non cambia!!

 ROTATE RIGHT (ROTAZIONE A DESTRA)


Consiste di uno spostamento a destra dei bit (i bit vengono traslati a destra).
I bit che escono a seguito di questa operazione dalla stringa vengono mandati
nel CARRY e poi reinseriti a sinistra della stringa, per occupare gli spazi vuoti
lasciati dalla traslazione.

 ROTATE LEFT (ROTAZIONE A SINISTRA)


Consiste di uno spostamento a sinistra dei bit (i bit vengono traslati a
sinistra). I bit che escono a seguito di questa operazione dalla stringa vengono
mandati nel CARRY e poi reinseriti a destra della stringa per occupare gli
spazi vuoti lasciati dalla traslazione.

 ISTRUZIONI DI CONTROLLO PROGRAMMA


Sono istruzioni che servono a modificare l’ordine di esecuzione sequenziale delle
istruzioni di cui è composto un programma. Esse sono suddivisibili in due categorie,
a loro volta suddivise in due sottocategorie. In generale sono dette anche istruzioni
di salto.
o Salto condizionato = si “salta” solo se la condizione espressa dal bit del
registro dei Flag è verificata.
o Salto Incondizionato = si “salta” comunque, a prescindere dal valore
presente nel registro dei flag.
o Ritorno Incondizionato = al termine dell’esecuzione del sottoprogramma,
si ritorna al Main Program riprendendo il lavoro in esecuzione dal punto
in cui era stato interrotto.
o Ritorno Condizionato = una volta effettuato non si ritorna all’istruzione
successiva del Main Program, a meno del verificarsi della condizione
imposta.
Analizziamo i vari casi con degli esempi.

 SALTO CONDIZIONATO SENZA RITORNO


Si tratta di quel caso in cui se viene verificata una certa condizione, allora
viene effettuato l’istruzione JUMP, nel seguente modo: Se la condizione è
verificata allora l’indirizzo corrispondente alla cella in cui è contenuta
l’istruzione da eseguire viene caricato nel Program Counter. Se la condizione
non è verificata, nella fase di fetch il program counter si aggiorna
automaticamente e si prosegue nell’esecuzione del main program, passando
all’istruzione successiva a quella attuale. Il salto se avviene è senza ritorno.

Ex. JP <COND><INDIRIZZO> cioè INDIRIZZO  PC

 SALTO INCONDIZIONATO SENZA RITORNO


Il salto avviene nel punto del programma prestabilito, sempre, dal momento
che non dipende dal verificarsi o meno di una data condizione. Il salto è senza
ritorno.

Ex. JP <INDIRIZZO> cioè INDIRIZZO  PC

 SALTO RELATIVO ALLA POSIZIONE ATTUALE DEL PC, SENZA RITORNO


Si tratta di un salto in avanti o indietro, rispetto alla posizione attuale del
Program counter, di un certo numero di celle/istruzioni che viene chiamato
DISPLACEMENT = spiazzamento, rappresentato in complemento a 2. In
pratica si dice al program counter di passare a un’istruzione successiva o
precedente a quella indicata dal PC in quell’istante, indentificando la nuova
istruzione come quella che “dista” un certo numero di istruzioni
(displacement) da quella attuale.

Ex. JP <DISPLACEMENT> cioè (PC) + DISPLACEMENT  PC

 SALTO RELATIVO CONDIZIONATO SENZA RITORNO


Procedimento analogo al salto relativo incondizionato descritto al punto
precedente, fatta eccezione per il fatto che il salto si verifica solo se è
soddisfatta la condizione imposta. Nel caso non lo fosse l’esecuzione del
programma procede, e il PC si aggiorna in automatico puntando all’istruzione
successiva da eseguire.

Ex. JP <COND><DISPLACEMENT> cioè (PC) + DISPLACEMENT  PC


Analizziamo ora i salti con ritorno. Si tratta di chiamate a sottoprogrammi, che una volta
eseguiti prevedono che la CPU ritorni all’esecuzione del Main Program dal punto in cui era
stata interrotta. Questo vuol dire che nel passaggio a una subroutine il contenuto del PC
non deve andare perso, perché sarà importante per poter ritornare all’esecuzione del main
program una volta terminata l’esecuzione del sottoprogramma, riprendendo l’attività dal
punto in cui era stata interrotta. Per questo scopo si opera come segue: il contenuto del PC
(che punta all’operazione successiva a quella attuale) viene salvato nello STACK, una parte
della memoria dedicata a questo scopo, e l’indirizzo della cella in cui si trova il valore del
PC sarà indicato dallo STACK POINTER. Se all’interno di un sottoprogramma è necessaria
un’altra operazione di salto, il procedimento viene ripetuto, solo che ora lo STACK POINTER
punterà all’indirizzo della cella di memoria nello stack che per ultima è stata riempita. Alla
fine della subroutine il PC salvato nello stack viene prelevato e salvato nel PC, a questo
punto lo SP si aggiorna per puntare all’ultima casella scritta non ancora prelevata, e il
procedimento prosegue, seguendo la logica LIFO (Last in First Out), secondo cui gli ultimi
valori caricati nello stack saranno i primi ad essere prelevati.
 SALTO CON RITORNO CONDIZIONATO
Funziona nella logica sopra descritta, e viene effettuato solo se si verifica una
certa condizione.

Ex. CALL <COND><INDIRIZZO>

(SP) – 1  SP Stack pointer incrementato (punta a una nuova cella della pila)
(SP)  MAR
(PC)  MBR (N.B. il PC contiene già l’indirizzo dell’istruz. Successiva!)
(MBR)  (MAR)

INDIRIZZO  PC

 SALTO CON RITORNO CONDIZIONATO


Come sopra, solo che deve verificarsi la condizione, cosa che viene espressa
da registro dei flag (verificata/non verificata)

Vediamo ora le istruzioni di ritorno.


 RITORNO CONDIZIONATO
Se la condizione è verificata allora si ritorna al punto in cui era stato
interrotto l’esecuzione del programma, altrimenti il PC punta già
all’istruzione successiva, e si prosegue.

Ex. RET <COND>

 RITORNO INCONDIZIONATO
Al termine dell’esecuzione di un sottoprogramma, si deve ritornare al punto
in cui era stato interrotto il lavoro. Pertanto bisogna recuperare dallo stack il
PC che punta all’istruzione successiva a quella del salto, che deve essere
eseguita. Per fare ciò il contenuto dello SP indica l’indirizzo della cella di
memoria dello stack che per ultima è stata scritta e il cui contenuto è
prelevato e messo nel PC. A questo punto lo stack pointer si aggiorna e punta
all’ultima cella di memoria scritta che non è stata prelevata, e in caso di più
nidificazioni del programma, il procedimento si ripete.

Ex. RET

(SP)  MAR
(MAR)  MBR
(MBR)  PC
(SP) +1  SP

 ISTRUZIONI DI CONTROLLO MACCHINA


Sono istruzioni che servono a modificare direttamente lo stato della CPU, senza
operare sui dati né sulle operazioni tra dati (trasferimenti, ecc.).

 HALT
Arresta il funzionamento della CPU

 NOP
Che sta per “No Operations”, mantiene inalterato lo stato della CPU, serve a
creare dei ritardi per permettere il completamento di altre operazioni.

 DI
Che sta per “Disable Interrupt”, comando che disattiva gli interrupt, così la
CPU non riceverà segnali di interrupt.

 EI
Che sta per “Enable Interrupt”, comando che attiva gli interrupt, così la CPU
potrà ricevere segnali di interrupt.

 RESET
Comando che azzera lo stato della CPU.

Considerazioni:
Ogni CPU influisce sul linguaggio ASSEMBLY che viene accettato, quindi CPU diverse
necessiteranno di modi diversi per rappresentare le stesse istruzioni, si parla così di
NON PORTABILITA’ DEI PROGRAMMI.
L’INTERRUPT è un segnale analogico creato da un trasduttore. Questo si genera
per la pressione di un tasto, ecc. convertito da un ADC in segnale digitale, a ogni
interrupt viene assegnato un indirizzo relativo alla TABELLA DEGLI INTERRUPT.
Ogni volta che la CPU riceve più interrupt, consulta questa tabella in modo da poter
stabilire la priorità relativa a ogni interrupt, occupandosi così prima della gestione
di quegli interrupt con elevata priorità (ex. La lama che si avvicina alle mani di un
operatore) e rimandando a dopo la gestione degli interrupt con minore priorità (Ex.
È finita la carta della stampante). Questa “selezione” viene gestita dai comandi DI e
EI.

Quando mettiamo un computer in STAND BY, ciò che facciamo è mandare alla CPU
un’istruzione di HALT, che congela i dati e arresta il funzionamento della CPU, che
rimane però attiva. Il comando e la CPU rimangono attivi fino a quando non
interviene un segnale di interrupt che corrisponde alla riaccensione del computer.
Sistema più efficace dei NOP e del POLLLING.

METODI DI INDIRIZZAMENTO

La memoria è divisa in byte, l’indirizzo corrisponde all’i-esimo byte della memoria, infatti
non è possibile assegnare un indirizzo a ogni singolo bit. Abbiamo visto che nell’esecuzione
del ciclo macchina alla CPU devono essere fornite delle istruzioni costituite da diversi parti:
il CAMPO OPERATIVO che contiene il codice operativo e il CAMPO OPERANDI che
contiene invece delle informazioni sugli operandi coinvolti in un dato calcolo, fornendo la
SORGENTE (dati su cui operare), il DESTINATARIO (dove porre il risultato) e la
MODALITA’ D’INDIRIZZAMENTO (ossia dove si trovano gli operandi e la cella di
destinazione). Sarà proprio quest’ultimo punto che ora analizziamo.
GRADO DI PARALLELISMO = numero di bit che possono essere scritti contemporaneamente
SPAZIO D’INDIRIZZAMENTO = numero di byte che possono essere indirizzati: 2N, con N
numero di bit usati come indirizzo. (oggi giorno abbiamo 64 bit su bus dati, quindi 264)

Un’istruzione può fornire gli operandi in modi diversi:

 IMMEDIATO
L’operando compare direttamente nell’istruzione come “costante”, svolgendo solo il
ruolo di sorgente.

 ASSOLUTO
Nell’istruzione viene riportato l’indirizzo effettivo (ossia fisico) [della cella (o delle
celle)] di memoria in cui si trova l’operando.

 RELATIVO
Nell’istruzione compare un numero che deve essere sommato al PC per trovare
l’indirizzo con l’operando (il numero rappresenta lo spostamento da attribuire al
PC, displacement). Questo permette di avere un programma indipendente dagli
indirizzi salvati nelle sue istruzioni, e quindi il programma può essere salvato in
qualunque parte della memoria.
 DIRETTO A REGISTRO
L’operando è contenuto in un registro, il cui identificatore è specificato
nell’istruzione

 INDIRETTO CON REGISTRO


L’operando si trova in memoria (in una cella o in una parte di memoria) il cui
indirizzo è salvato in un registro, il cui identificatore è specificato nell’istruzione.

 CON AUTOINCREMENTO (O POSTINCREMENTO)


Analogo all’indiretto con registro, ma il contenuto del registro prima viene usato per
indirizzare la memoria e poi incrementato della dimensione dell’operando.

Ex.
Operando di 32 bit  4 byte
(Reg0) = 1000 indirizzo della cella di memoria che contiene operando
(Reg0)  MAR
((MAR))  MBR
(MBR)  ALU (Reg0) + 3  Reg0 cioè Reg0 = 1004

(leggo il valore e poi incremento il registro, in modo da leggere il valore successivo),


(indirizzo 1004 per istruzione successiva).

 CON AUTODECREMENTO (O PREDECREMENTO)


Simmetrico al precedente, ma, il contenuto del registro viene prima decrementato
di un numero pari alla dimensione in byte dell’operando e poi usato per indirizzare
la memoria.

 INDIRETTO CON AUTOINCREMENTO


L’operando è in memoria, l’indirizzo della parte/cella di memoria in cui si trova
l’operando si trova in un’altra parte della memoria, puntata dal contenuto di un
registro. Nell’istruzione viene specificato l’identificatore del registro. Dopo aver
indirizzato il modo indiretto l’operando, il contenuto del registro (che ora è
l’indirizzo della cella dell’operando, NON l’indirizzo della cella che contiene
l’indirizzo!) viene incrementato di un numero pari alla dimensione in byte di una
cella di memoria atta a contenere il nuovo indirizzo.

Ex.
Leggo l’indirizzo nel registro e vado alla zona di memoria indicata. Prelevo (cioè
metto nel registro) il puntatore alla casella che contiene l’operando, vado in quella
casella e prelevo l’operando. Ora il registro si incrementa di un numero pari alla
dimensione in byte occupata da un indirizzo in memoria, così da puntare
all’indirizzo successivo (nell’esempio 2000).
Cella 500
Registro N
1000 Cella 1000
500
2000 ..

3000 Cella 4000


4000 ….

L’istruzione porta al registro 500 ….

dal registro 500 indirizzo la memoria in maniera indiretta, quindi carico ….


Nel registro il valore 1000, relativo al primo operando che recupero.
Cella 2000
Il registro si incrementa automaticamente di 1000, puntando alla cella
….
Di indirizzo 2000, che è il nuovo indirizzo, relativo al nuovo operando

Presente nella cella 2000. Cella 3000


1000 è il numero di byte occupati da un indirizzo nell’esempio, e quindi il

Suo displacement. E via dicendo

 CON SPAZIAMENTO
Nell’istruzione sono presenti un dato in complemento a 2 e l’identificatore di un
registro che contiene un indirizzo. Il dato viene sommato al contenuto del registro
e si ottiene l’indirizzo dell’operando (il quale si trova in memoria).

 INDIRETTO CON SPAZIAMENTO


Come nel caso precedente, ma la somma ottenuta è l’indirizzo di una parte della
memoria che contiene l’indirizzo dell’operando. (ossia dalla somma ottengo
l’indirizzo che punta alla posizione di memoria che contiene l’indirizzo
dell’operando).

 IMPLICITO
Indirizzamento previsto per quelle operazioni il cui codice operativo sottintende
l’uso di registri. Tipicamente in questo indirizzamento l’accumulatore è coinvolto
come sorgente di uno degli operandi, e come destinazione del risultato.

Ex.

ADD <INDIRIZZO>ACC cioè (INDIRIZZO) + ACC  ACC

 CON REGISTRI INDICE


L’istruzione usa due registri, uno che contiene l’indirizzo base (registro di cui
istruzione fornisce l’identificatore), l’altro registro identificato contiene un numero.
Questo numero va moltiplicato per il numero di byte (dimensione) dell’operando, e
poi sommato all’indirizzo contenuto nel primo registro, e ottengo l’indirizzo
dell’operando.
Utile per lavora con matrici e tabelle.
Ex.
(REG A) + [(REG B) × n° Byte di A] = INDIRIZZO operando

[A contiene un indirizzo, quindi n° Byte A è il numero di Byte (dimensione)


dell’indirizzo!)

 CON LO STACK POINTER


Lo stack pointer punta alla sommità dello stack. Questa modalità di indirizzamento
è utile per la gestione delle chiamate a sottoprogrammi e a subroutine. Mediante
istruzioni di PUSH è possibile inserire il contenuto di registri nello stack e con
operazioni di POP prelevare dati dallo stack per immagazzinarli in registri. Lo SP
punterà sempre alla cima della pila (stack). Utile e veloce, usata per interrupt. Così
non specifico l’indirizzo di memoria che è già sottointeso.

 PUSH:
(RegN) = INDIRIZZO

(SP) +1  SP
(RegN)  PILA
(SP)  MAR
((MAR))  MBR ho trovato l’operando.

(metto contenuto del registro nello stack, il SP punterà alla cella che lo contiene
(cima della pila), e quindi posso prelevarlo e portarlo alla CPU, che poi recupererà
leggendolo l’operando)

 POP:
(SP) + 1 = INDIRIZZO

(SP) + 1  SP
(PILA)  RegN
(SP)  MAR
((MAR))  MBR ho trovato l’operando.

(metto l’indirizzo nello stack pointer esso mi identifica la cella dello stack
corrispondente (cima dello stack, a cui SP punta). Metto il contenuto della PILA
(cima dello Stack) nel registro N.

IN GENERALE:
PUSH = aggiunge un dato alla cima dello stack
POP = toglie un dato dalla cima dello stack

(criterio adottato = FIFO (First In First Out))

MEMORIE

Ritornando alla struttura della macchina di Von Neumann, analizziamo ora una
componente indispensabile in ogni calcolatore che è la MEMORIA. Lo scopo della memoria
è quello di archiviare/memorizzare i dati forniti ed elaborati dal calcolatore. Ci sono
diverse tipologie di memoria, che sono basate su diverse tecniche di memorizzazione delle
informazioni digitali:

MEMORIE A SEMICONDUTTORE e le MEMORIE MAGNETICHE.


Entrambe le due memorie si basano su BISTABILI, ossia su elementi caratterizzati da un
diagramma energetico del tipo:

Questo diagramma energetico presenta due minimi relativi separati da un massimo relativo
che presenta un’ampiezza significativa. I bistabili sono elementi in grado di permanere in
uno dei due stati stabili (cioè di minima energia) per un tempo indeterminato, fino a che
non interviene un fenomeno di entità sufficiente a far sì che lo stato dell’elemento cambi.
Si associa convenzionalmente a uno stato il valore 1 e all’altro il valore 0, e quindi ora è
possibile memorizzare informazioni binarie. (1 bit per ogni bistabile).
N.B. il picco di massimo tra i due stati deve essere sufficientemente alto in modo da non
avere transizioni di stato non volute o forme di incertezza sullo stato. Più alto è più
energia servirà per cambiare stato (eventuale svantaggio).

Le memorie vengono anche suddivise sulla base di:


 Modalità di Accesso (a cui è legata la velocità di risposta)
 Stabilità delle informazioni memorizzate

MEMORIE A SEMICONDUTTORE

 MEMORIE RAM (RANDOM ACCESS MEMORY)


Sono di varie tipologie:

 STATICHE  SRAM
1) La cella elementare che memorizza un bit è costituita da un circuito con
diversi transistor (formata cioè da dispositivi attivi). Un bit = 6 transistor.
2) Modalità di accesso casuale (capacità di accedere direttamente alle celle in
qualsiasi ordine; il tempo impiegato per raggiungere una cella è uguale
per tutte le celle, senza distinzioni, in questo senso “casuale”).
3) L’informazione viene mantenuta fino a quando sono alimentate.
4) Più veloci delle DRAM, più costose e di minore capacità.

Per non perdere informazioni, ogni tot. tempo devo vedere in che stato è
la carica e ricaricare all’occorrenza.
Vantaggi: posso creare grandi capacità di memoria.
Svantaggi: è una memoria volatile.

 DINAMICHE  DRAM
1) Per immagazzinare un bit basta un solo transistor, unito a un
condensatore. Il condensatore idealmente manterrebbe la carica
all’infinito, ma in un sistema fisico non è così e con il passare del tempo
si scarica (a causa del transistor, anche a sistema aperto), da cui segue il
punto 2.
2) L’informazione tende a cancellarsi, quindi ogni msec l’informazione deve
essere riscritta (rinfrescata). Operazione gestita dal “Controllore della
DRAM” ossia il <Dynamic RAM Controller>. Il controllore, per non entrare
in conflitto con la CPU, ne monitora le attività. Quando la CPU lavora
internamente, senza l’impiego della memoria, allora il controllore esegue
le operazioni di riscrittura.

 RAM SINCRONE (SSRAM e SDRAM)


Sono memorie in grado di trasferire blocchi di dati presenti in memoria a
indirizzi consecutivi, bisogna specificare l’indirizzo di partenza e la
lunghezza. Una volta generato il primo indirizzo, il segnale di clock
sincronizza la sequenzializzazione dei dati.
1) Viene mandato un indirizzo alla RAM
2) La memoria lavora con un orologio interno
3) Ogni periodo di clock passa da un blocco di dati a un altro.

Vantaggi = trasferimento più veloce dei dati

 MEMORIE ROM (READ ONLY MEMORY)


Sono memorie a sola lettura, che contengono in genere programmi per il
funzionamento di applicazioni embedded o programmi di inizializzazione dei
calcolatori. I programmi contenuti non sono in alcun modo modificabili in genere.
Mantengono l’informazione anche se non alimentate
Vantaggi = economiche e affidabili

 ROM
Informazione viene scritta durante la fabbricazione e non si può modificare
in alcun modo.

 PROM  PROGRAMMABLE ROM


1) Possono essere scritte una sola volta dall’utente con un’apparecchiatura
della “Programmatore PROM”.
2) La memoria viene fornita con incroci formati da fusibili. Questi vengono
o meno bruciati, memorizzando in maniera permanente i programmi. (la
rottura del fusibile viene creata da Programmatore PROM. Vengono così
infatti memorizzati gli 0 e gli 1.
 EPROM  ERASABLE PROGRAMMABLE ROM
Può essere programmata dall’utente, e può essere anche cancellata. Infatti il
contenitore delle EPROM è dotato di una finestrella trasparente che permette
di cancellare le informazioni memorizzate mediante l’esposizione alla luce
ultravioletta del chip (EPROM) al suo interno. La procedura è eseguibile più
volte.
Vantaggi = dispositivo riutilizzabile
Svantaggi = con la luce si cancella

 OTP PROM  ONE TIME PROGRAMMABLE ROM


Sono identiche nella struttura alle EPROM, ma non sono dotate di una
finestrella trasparente. Utilizzate per memorizzare definitivamente i
programmi realizzati sulle EPROM una volta conclusi e resi stabili.

 EEPROM  ELETTRICALLY ERASABLE ROM


Uguali alle EPROM, ma la cancellazione viene effettuata con segnali elettrici.

 EAROM  ELETTRICALLY ALTERABLE ROM


Sono memorie ROM che possono essere cancellate in parte (anche solo poche
celle) mediante segnali elettrici. (quindi non devo per forza cancellare tutta la
memoria, ma posso cancellare quello che mi interessa).

 FLASH
1) Cancellabili mediante impulsi elettrici
2) Permettono cancellazioni parziali, direttamente su scheda, rapide
3) Non utilizzabili sulla CPU perché sono rapide e leggere, ma lente nella
scrittura, e quindi ridurrebbero le prestazioni della CPU.

Vantaggi = più veloci delle EPROM


Svantaggi = abbastanza costose; con l’uso prolungato e molte
cancellazioni e sovrascritture si danneggiano.

MEMORIE A SUPPORTO MAGNETICO

I bistabili sono costituiti da strati di materiale ferromagnetico depositato su un supporto


plastico o ceramico che viene portato in movimento al di sotto di un dispositivo
elettromagnetico (testina di scrittura e lettura).
Dette anche MEMORIE DI MASSA, sono memorie non volatili. Ci sono diverse tipologie di
memorie magnetiche, ma il principio di funzionamento è lo stesso.
Esistono due stati stabili corrispondenti ai due versi di magnetizzazione del materiale
ferromagnetico

SCRITTURA = nella bobina (spira) passa della corrente, questa genera un campo magnetico
concatenato alla spira. Le linee del campo magnetico vengono veicolate all’interno della
testina ferromagnetico. Il campo magnetico colpisce la zona di mio interesse imprimendo
a ogni sezione del supporto ferromagnetico in movimento una polarizzazione “  “ che
per convenzione faremo corrispondere allo 0, e “ “ che faremo corrispondere all’1. Cioè
al passaggio della testina ogni areola si magnetizza per effetto del campo magnetico
generato dalla spira della testina.

LETTURA = avviene allo stesso modo. Al passaggio delle areole magnetizzate sotto la
testina, il campo magnetico memorizzato da ogni areola induce un campo magnetico nella
testina di lettura/scrittura diretto nello stesso verso. Questo a sua volta concatenandosi
con la spira genera una corrente indotta. A seconda del verso del campo magnetico cambia
il verso della corrente indotta e quindi è possibile leggere ogni stato magnetico come 0 o
1.

Per cancellare induco un altro campo magnetico. È utile che le areole siano sufficientemente
piccole, in modo da poter memorizzare molti dati, ma non troppo, per evitare che areole
vicine in fase di scrittura possano subire involontariamente polarizzazioni sbagliate. Posso
quindi, entro certi limiti, diminuire le dimensioni di ogni sezione, della testina e diminuire
la corrente per avere meno interferenze (così aumento la capacità dei dischi).

Svantaggi = siccome sono presenti componenti meccaniche, queste possono guastarsi. Non
sono memorie veloci, perché per recuperare un dato bisogna aspettare che il disco e la
testina siano allineati e pronti per la lettura. Non sono veloci perché il movimento del
supporto deve essere tale da far sì che supporto e testina non si tocchino, quindi sono
sistemi anche delicati. Tempi dell’ordine di 10-2.
Vantaggi = memorie non volatili, e una volta in posizione i dati vengono trasferiti e
memorizzati a grande velocità

In base al supporto abbiamo varie memorie magnetiche:

 FLOPPY DISK (DISCHI FLESSIBILI)


Come gli Hard Disk, ma dal supporto flessibile. Sono estraibili dalla macchina per il
trasferimento di informazioni tra calcolatori. Generalmente sono dischi fermi a
testina mobile. Richiedono così più tempo. (per posizionamento testina e recupero
informazioni).

 HARD DISK (DISCHI RIGIDI)


Materiale ferromagnetico disposto su un disco rigido realizzato in leghe di alluminio
o vetro in rotazione a velocità costante attorno al proprio asse. Ogni superficie è
divisa in corone concentriche (testina in comune, quindi mobile, o testine dedicate
a ogni corona). La testina è a pochi micron di distanza dal disco. Ogni unità può
essere caratterizzata anche da più dischi coassiali (impilati) con più testine.
Realizzati in camere apposite per evitare che la polvere possa depositarsi sul disco.
Dischi a testine fisse sono i più veloci, ma ci sono anche diffusi dischi fissi a testine
mobili.

 MEMORIE RAID
Insieme di dischi rigidi collegati tra loro, usate per proteggere i dati in caso di
malfunzionamento del disco rigido. I dati sono distribuiti su più dischi (ridondanza)
per essere recuperati in caso di guasti.

 NASTRI MAGNETICI
Il materiale ferro magnetico è depositato su nastri di plastica avvolti in bobine,
suddivise in strisce parallele (generalmente 9), ciascuna assegnata a una testina, che
consentono di memorizzare un byte con un bit di parità. Longitudinalmente i nastri
sono divisi in blocchi da zone non magnetizzate.

MEMORIE OTTICHE

Sono basate su bistabili costituiti da deformazioni permanenti (buchi detti “pit”) apportate
durante la fase di scrittura alla struttura meccanica di supporto (solitamente in materiale
plastico).

SCRITTURA = un raggio di luce concentrato generato da un laser incide la superficie del


disco, creando i pit, e quindi deformando la superficie del disco.
LETTURA = in presenza di una superficie non deformata incidendo con un raggio a minor
energia, l’energia viene riflessa verso il fotorilevatore; in presenza di una deformazione
l’energia luminosa viene invece diffusa, giungendo in minima parte al foto rilevatore. Il
fotorilevatore, mediante alti o bassi valori di tensione elettrica generati dalla luce percepita
è in grado di riscostruire le informazioni sul disco.

 CD-ROM
Sono memorie a sola lettura, senza la possibilità di cancellazione. In generale visto
che possono essere scritte una volta, ma possono essere lette molte volte vengono
chiamate WORM (Write One Read Many).
Sul disco è presente un’unica traccia avvolta a spirale, hanno elevata capacità ma con tempo
di accesso relativamente lunghi.
 MAGNETO-OPTICAL
Sandwich di policarbonato e materiale magnetico. Il punto riscaldato dal laser
assume la stesa polarità del campo magnetico applicato dalla testina. Può essere
cancellato e riscritto.

 CD-RW
Dischi ottici per la memorizzazione dei dati. “CD ReWritable”. Sono cancellabili e
riscrivibili, per archiviazione dati e prototipi di CD-ROM. Riscrivibile direttamente
senza cancellazione. Questo perché costituiti da un sandwich di selenio o tellurio e
policarbonato, che riscaldato o meno assume due stati = AMORFO o CRISTALLINO.
Incidendo con potenze diverse si passa da uno stato all’altro.

 DVD
Dischi a memoria ottica molto più capienti formato da strati di policarbonato, uno
strato semiriflettente e uno strato completamente riflettente. Usati anche su due
facce.

TIPI DI ACCESSO ALLA MEMORIA

 UNIFORME O CASUALE = caratteristico della RAM, l’accesso ai dati avviene tramite


il loro indirizzo in un tempo costante e uguale per tutti, che quindi non dipende
dalla posizione dei dati.

 SEQUENZIALE = caratteristica dei nastri, i dati vengono letti e scritti in sequenza

 DIRETTO O MISTO = tipico dei dischi. Si accede direttamente ai dati, ma il tempo


di accesso varia a seconda della posizione relativa tra dato e testina di
scrittura/lettura.

MEMORIA CENTRALE E MEMORIA DI MASSA


Una domanda chiave che dobbiamo farci è: ma costruendo un calcolatore, quale memoria
conviene utilizzare? Qual è la migliore?
In realtà la risposta è DIPENDE. Infatti ogni memoria ha le sue caratteristiche, che possono
avere molti vantaggi su un fronte, ma anche non trascurabili svantaggi sull’altro fronte.
Quindi noi doteremo il calcolatore del meglio di ogni dispositivo di memoria, facendo
in modo che agli occhi della CPU compaia una sola memoria.
Ogni memoria ha delle caratteristiche che la rendono importante nell’utilizzo in un
calcolatore, vediamo in un grafico riassunte le varie proprietà.
È evidente notare che non tutte le memorie sono veloci, ma un altro parametro da valutare
è la volatilità delle informazioni memorizzate. Notiamo che le memorie più veloci sono
anche quelle volatili, quindi non possono essere usate da sole, ma dovremmo usare anche
memorie magnetiche per conservare i dati a dispositivo spento. Inoltre i dispositivi a
semiconduttore costano, e averne in grandi quantità crea una spesa troppo elevata.

Avere un’ampia disponibilità di memoria è utile in quanto consente di avere uno spazio
d’indirizzamento più ampio, permettendo di usare strutture dati più complesse, ma anche
è utile per quei calcolatori il cui uso è condiviso da più utenti, che dovranno mantenere in
memoria i propri dati e programmi.
Non è però possibile usare solo memorie a supporto magnetico, perché sono molto lente
(tempi dell’ordine dei 10-2) e sono quindi incompatibili con i tempi della CPU. La CPU
internamente lavora con tempi dell’ordine dei 10-8 e talvolta dei 10-9.
Inoltre la distribuzione degli indirizzi durante l’esecuzione di programmi non è casuale,
ma esiste un’alta probabilità che da un certo indirizzo in poi ne venga generato uno uguale
o simile. Questo comportamento è descritto dal:
PRINCIPIO DI LOCALITA’ DEGI ACCESSI

 Località temporale = ogni programma ha un’elevata probabilità di riutilizzare a


breve le informazioni appena acquisite.
 Località Sequenziale = l’esecuzione di un’istruzione ha un’elevata probabilità di
essere seguita dall’istruzione successiva nel programma.

Questo principio permette di poter introdurre una GESTIONE VIRTUALE DELLA


MEMORIA di lavoro. Grazie a questa organizzazione lo spazio utilizzabile da un
programma è largamente superiore a allo spazio fisico attribuitogli effettivamente nel
calcolatore (memoria centrale), nel quale vengono temporaneamente ricopiate dalla
memoria di massa le informazioni usate in quel momento dalla CPU.
Il termine virtuale deriva dal fatto che in questa organizzazione della memoria lo spazio
di indirizzamento della CPU non ha un riscontro fisico nella RAM, che è solo una parte
della memoria reale del sistema, ma fa riferimento a una memoria di lavoro virtuale
(memoria di massa).
La CPU crede di comunicare con la memoria di massa, mentre invece questa è solo una
memoria virtuale di lavoro, poiché in realtà la CPU si trova a comunicare con la RAM, che
ha tempi di risposta consoni ai tempi di lavoro della CPU. Serve allora uno strumento per
convertire L’INDIRIZZO VIRTUALE emesso dalla CPU in un INDIRIZZO FISICO della cella di
lavoro in cui è stato ricopiato il dato cercato.
Questo compito descritto è demandato all’UNITA’ DI GESTIONE DELLA MEMORIA (MMU).

 Quando la CPU richiede l’accesso a una porzione di memoria virtuale non presente
in una cella di memoria reale, cioè nella RAM, viene effettuata una ricopiatura della
porzione desiderata della memoria dalla memoria di massa alla RAM. A questo
punto il MMU (Memory Management Unit) converte l’indirizzo virtuale emesso dalla
CPU in indirizzo fisico, permettendo l’accesso della CPU ai dati. Il processo inverso
consente di liberare spazio nella RAM (“swapping”). Si usa il principio di località
degli accessi = viene ricopiata la parte di memoria richiesta, insieme alle porzioni
adiacenti, che secondo il principio hanno più elevata probabilità di essere richieste
dalla CPU/programma in esecuzione.

MEMORIA DI MASSA (Virtuale)


La CPU vuole andare qui (Ind. Virtuale)
CPU …


Indirizzo virtuale RAM
Blocco richiesto dalla CPU
….
MMU

* …..
Blocco richiesto dalla CPU
…..
Indirizzo fisico …..
……
…..
…..

…..

…..
* Ricopiato nella RAM

Vantaggio = si guadagna tempo perché la CPU non deve adattarsi ai tempi della memoria
di massa
Svantaggi = Quando devo liberare la RAM per fare spazio ad altri programmi, devo tenere
conto di cosa è stato modificato e cosa no.
N.B. L’indirizzo fisico conterrà un numero di bit minore dell’indirizzo virtuale, perché è una
memoria più ridotta.
Esistono varie modalità di gestione della memoria.
 PAGINAZIONE

Metodo di gestione della memoria basato sul concetto di:

PAGINA = blocchi di memoria di pari dimensione, solitamente pochi Kbyte

(blocco di parole consecutive di dimensione prefissata (pochi Kbyte) che costituisce


l’unità minima di informazione trasferita dalla memoria di massa alla memoria
centrale e viceversa.)

In questa modalità la memoria centrale e la memoria di massa vengono divise in


blocchi di uguale dimensione (in pagine di uguale dimensione). Ogni programma
occupa in genere più pagine, non necessariamente consecutive. Solitamente un
programma non richiede l’accesso a tutte le pagine che lo compongono, per questo
motivo dividere un programma in blocchi/pagine è un vantaggio, perché permette
di evitare di caricare in memoria tutto il codice e i dati di un programma.
L’operazione di conversione dall’indirizzo virtuale a quello fisico vuol dire andare a
trovare la posizione occupata da una pagina nella memoria centrale dopo essere
stata copiata.
Viene così costruita una TABELLA DI CORRISPONDENZA tra pagine virtuali e
fisiche. È così costruita

1) Una colonna occupata da un bit indica se la pagina e presente nella memoria


centrale o se non è presente.
2) Se la pagina è presente indica la posizione nella quale si trova (indirizzo fisico).

Quando la CPU consulta la memoria, questo comporta la lettura della tabella: se la


pagina è presente allora l’indirizzo fisico è ricavabile dalla tabella; se la pagina non
è presente, questa deve essere caricata dalla memoria di massa. Va quindi
identificata un’area libera della memoria centrale in cui copiare la pagina richiesta.
Alla tabella vanno aggiunte altre due informazioni utili:

3) Una colonna occupata da un bit che indica se la pagina è stata modificata, oppure
non è stata modificata.
4) Una colonna che indichi mediante una stringa di bit quanto tempo è passato
dall’ultima consultazione di una data pagina.
Queste informazioni sono importanti. Considerando il caso che la pagina richiesta
non sia presente, essa deve essere ricopiata nella memoria centrale. Se non c’è spazio
per copiarla, bisogna eliminare delle pagine. Il criterio usato per l’eliminazione di
pagine dalla memoria centrale è quello descritto dalla formula LRU “Least Recently
Used”. Ossia, vengono eliminate per prime quelle pagine che non vengono consultate
da tanto tempo. Una volta individuate queste pagine, prima di eliminarle devo vedere
se sono state apportate delle modifiche alle stesse. In caso affermativo la pagina,
prima di essere eliminata, viene salvata nella memoria di massa (sovrascritta), e poi
eliminata dalla memoria centrale. Nel caso non siano state apportate delle modifiche
invece la pagina viene semplicemente eliminata.
Svantaggi = blocchi grandi di memoria possono contenere dati che hanno la
probabilità di non essere usati, quindi avrei uno spreco di spazio. All’opposto
blocchi molto piccoli renderebbero difficile la trasformazione degli indirizzi. Altro
svantaggio è l’eccessiva dimensione della tabella quando lo spazio di indirizzamento
virtuale e molto esteso.
ESEMPIO NUMERICO SULLA PAGINAZIONE
Dimensione RAM (memoria centrale) = 8 GB
Dimensione Memoria di Massa = 1 TB
Dimensione Pagina = 1 KB

1) N° di bit indirizzo virtuale

1 TB = 240 bit  40 bit per l’indirizzo virtuale

2) N° di bit indirizzo fisico


8 GB = 8 × 230 bit = 233 bit  33 bit per l’indirizzo fisico

3) N° pagine virtuali

1 TB : 1 KB = 240 bit : 1024 Byte = ( 240 ∶ 210 ) bit = 230  230 pagine virtuali

4) N° pagine fisiche

8 GB : 1 KB = 233 bit : 210 bit = 223 bit  223 pagine fisiche

5) Dimensione tabella di conversione (N° righe e N° colonne)

Il numero di righe sarà il numero di pagine virtuali raggiungibili  230 righe


Il numero di colonne sarà dato dai bit dell’indirizzo fisico, a cui aggiungo il bit
della presenza, della modifica e una sequenza che tiene conto del bit del tempo.
Senza queste variabili avrei  23 bit per riga

N.B. dall’indirizzo fisico a quello virtuale c’è uno scarto di 10 bit. Ma dove
finiscono? Quando creo l’indirizzo fisico prendo i 10 bit meno significativi (in
questo caso) della sequenza e i rimanenti 23 mi costituiranno l’indirizzo fisico
della pagina.

30 10 bit meno significativi

23 10 bit meno significativi

Identificativo blocco identificatore casella nel blocco

(conversione da indirizzo virtuale a indirizzo fisico)

 SEGMENTAZIONE

Altra tecnica di gestione della memoria, basata sul concetto di:

SEGMENTO = modulo che compone un programma, struttura dati usata da


programma, ossia un blocco logicamente separato dagli altri.

La logica dell’uso di segmenti è basata sulla volontà di copiare in memoria centrale


quei moduli che verranno usati dal programma, anziché copiare delle pagine, che
contengono spesso dati e programmi non utilizzati né richiesti dal programma in
esecuzione, e portano via spazio nella memoria.
I segmenti sono blocchi che presentano dimensioni diverse, e sono blocchi
logicamente separati.
La conversione dell’indirizzo virtuale prevede la presenza di una TABELLA DI
CONVERSIONE che porti al suo interno un bit di presenza, l’indirizzo fisico del
segmento e la lunghezza di questo segmento.

Se il segmento è presente, dalla tabella è ricavabile l’indirizzo fisico corrispondente


alla posizione del segmento in memoria centrale.
Se il segmento non è presente deve essere caricato in memoria dalla memoria di
massa. Siccome i segmenti hanno lunghezze diverse, la suddivisione della memoria
centrale è più articolata.

Problema = seguendo sempre la logica LRU (Least Recently Used), ma siccome i


blocchi hanno dimensioni differenti, è possibile che dei blocchi vengano ricopiati
nello spazio lasciato da blocchi di dimensioni maggiori. Questo comporta la
presenza di aree di memoria inutilizzate.
Soluzione = siccome dopo un certo numero di swapping la memoria risulta
frammentata, sono cioè presenti vari buchi, piccoli ma tanti (e nel complesso
riducono di molto lo spazio di memoria utilizzabile), deve essere effettuata una
compattazione periodica, che consiste di una ricopiatura periodica dell’intera
memoria in modo che vengano eliminate le aree inutilizzate della memoria fra i
blocchi.
SVANTAGGIO = la compattazione è un’operazione molto lenta.

 SEGMENTAZIONE PAGINATA

Questo metodo si situa a metà tra la paginazione e la segmentazione, ed è stato


introdotto per minimizzare gli effetti negativi di entrambe le organizzazioni
precedenti, cercando di conciliarne gli aspetti positivi.

Divisione della memoria in segmenti di lunghezza variabile, suddivisi però in


pagine di lunghezza fissa, non necessariamente consecutive.

La TABELLA DI CONVERSIONE prevede due livelli di analisi: un primo livello che


identifica la posizione del blocco, e un secondo livello che identifica la posizione
della pagina nel blocco/segmento.
Vantaggi = gestione efficiente della memoria, che elimina i problemi di
frammentazione, poiché i vari segmenti con le rispettive pagine, seppur fisicamente
non consecutive, vengono intese come “Logicamente Consecutive”. Viene mantenuta
una visione segmentata della memoria, ma anche una relativa compattazione.
Svantaggi = la conversione degli indirizzi diventa più complicata.

GERARCHIA DELLA MEMORIA

La gestione virtuale della memoria consente di dotare il dispositivo/calcolatore di una


struttura di memoria avente la capacità di memorizzazione del dispositivo di memoria più
grande e lento, ma con tempi di accesso che sono di poco superiori a quelli tipici del
dispositivo di memoria più piccolo e veloce.
Nasce così l’idea di una Gerarchia della Memoria:
- Le informazioni vengono memorizzate nel dispositivo più economico, grande e lento
(CD, nastro)
- Una parte delle informazioni di uso quotidiano viene ricopiata nel dispositivo più
piccolo e più veloce del nastro, ossia il disco.
- Le informazioni quotidiane usate dai programmi in esecuzione è ricopiata nelle lente
memorie a semiconduttore (ma ampie) (DRAM)
- Di quest’ultima parte, le informazioni di uso corrente (es. istruzioni ciclo macchina)
sono ricopiate nelle memorie a semiconduttore veloce (più piccole) (SRAM, statiche).

Per i primi due gradini della gerarchia non ci sono particolari problemi, il trasferimento di
dati da nastri a dischi, e viceversa, può essere fatto da operatori umani.

Per gli altri due gradini della scala il discorso cambia. Sono memorie che vengono rallentate
dal colloquio con le memorie più grandi e lente, quindi necessitano di dispositivi veloci per
funzionare a pieno ritmo. Non sono però adatte a costituire da sole la memoria di un intero
calcolatore, perché hanno dei limiti (memoria volatile). Nei calcolatori allora si introducono
entrambe le memorie a semiconduttore.

Si parla così di MEMORIA CACHE = memorie a semiconduttore dei due tipi unite a formare
una memoria centrale con velocità paragonabili a quelle delle memorie veloci, e capacità di
memorizzazione paragonabili a quelle delle memorie a semiconduttore lente.

 MEMORIA CACHE

è una memoria veloce relativamente piccola, non visibile al software, cioè


completamente gestita dall'hardware, che memorizza i dati più recentemente usati
(MRU - Most Recent Used) della memoria principale (MM - Main Memory) o memoria
di lavoro del sistema (centrale).
La memoria cache fa uso della tecnologia veloce SRAM contro una più
lenta DRAM della memoria principale, connessa direttamente al processore.

Utile = l’accesso a memoria grande e lenta (MM, memoria centrale) viene iniziato in
parallelo alla ricerca nella cache. Ossia: quando la CPU richiede un certo dato, la
ricerca inizia contemporaneamente nella memoria grande e lenta e nella cache. Se il
dato è nella cache ho guadagnato tempo, se non è così comunque si raggiunge la
cella nella memoria grande e lenta senza rallentamenti dovuti alla presenza della
memoria cache.
Abbiamo cioè inserito un parallelismo a livello di accesso alla memoria di lavoro.
Nel peggiore dei casi infatti la CPU otterrebbe il dato richiesto nel tempo che sarebbe
necessario per accedere alla memoria di lavoro usuale.

Inoltre è utile perché la circuiteria di questa memoria, fra un accesso e l’altro, lavora
in parallelo alla CPU portando nelle SRAM, piccole e veloci, le informazioni che
hanno più elevata probabilità di essere usate nel futuro prossimo dalla CPU,
effettuando cioè un trasferimento a pacchetti con la memoria di lavoro.

Vantaggi = può far guadagnare tempo, altrimenti impiegato nella ricerca dei dati
nella memoria centrale.

ESEMPIO GRAFICO GERARCHIA DELLA MEMORIA

Memoria Centrale Memoria di Massa


Memoria Cache
.. …

… …

.. //////////////////////
////////////////
///////////////////////// ….

///////////////////////// …

….. ….

…... …

(Cache = SRAM)

(Memoria centrale = DRAM)


(Memoria di Massa = Hard disk)

EVOLUZIONE MACCHINA DI VON NEUMANN

Prima di vedere l’evoluzione in senso stretto della macchina di Von Neumann andiamo a
fare delle considerazioni sulle interfacce di comunicazione.
INTERFACCE DI COMUNICAZIONE
La CPU di ogni calcolatore deve avere la possibilità di acquisire dati non solo internamente
dalle memorie, ma spesso deve essere in grado di comunicare con l’esterno, ossia con le
periferiche.
INTERFACCIA = dispositivo, fisico o virtuale, che permette l'interoperabilità fra due o
più sistemi di tipo diverso; ogni sistema espone una sua faccia, e il dispositivo viene
interposto fra di esse creando un punto comune.
SCOPO = dobbiamo trovare un modo per collegare un ambiente SINCRONO, preciso, dove
nulla è lasciato al caso, con un ambiente ASINCRONO, qual è la realtà. Per questo
introduciamo le interfacce (2 facce, una rigorosa interna, e una che tiene conto della
casualità del mondo esterno).
Inoltre non possiamo mandare i bus lontano per colloquiare con ogni dispositivo, perché si
generano delle interferenze reciproche tra i fili.
1) Interfacce parallele
 Cavi con molti fili in parallelo, posso trasferire più bit in parallelo;
 Sono più veloci (conseguenza del punto sopra)
 Come conseguenza del primo punto possono generarsi fenomeni di
interferenza fra cavi. La soluzione consiste nello schermare i cavi, ma è
costoso e creerebbe un grosso cavo rigido;
 Usato per brevi distanze (pochi metri)
 Trasmissione avviene in digitale (potrei separare livello alto da quello basso
per ridurre interferenze, ma consumerebbe più energia)

Standard: CENTRONCS, IEEE 488 (più periferiche sullo stesso canale)

2) Interfacce seriali
 Utilizzo un solo filo, o comunque pochi fili. Trasmetto cioè pochi bit o un
solo bit alla volta;
 Sono più lente:
 Coprono notevoli distanze;
 Servono due fili, uno per le informazioni da trasmettere, l’altro per le
destinazioni.
Problema = come faccio ad evitare interferenze?
1) Allargo gli estremi dell’intervallo di trasmissione e ne metto uno positivo e
uno negativo (*)
2) Uso due linee una a livello alto e una a livello basso (**)
Ex. ----------------------------- + --------------------------- -
----------------------------- - --------------------------- +
“1” “0”

3) Uso un anello di corrente, e in base al verso avrò 0 o 1. (***)

Standard:
CURRENT LOOP (1 Km, con 1200 bit per secondo) (***)
RS 232 (lavora tra -12V e +12V, 100 m con 19200 baud) (*)
RS 422 (1 Km, con 100'000 baud, con due linee per compensare disturbi) (**)
USB 1/USB 2 (3,5 m con 1,5/480 Mbit/s) molto veloce, distanze piccole.

N.B: USB sta per Universal Serial Bus


La CPU comunica anche con delle periferiche particolari, che sono i dispositivi presenti
all’interno di un calcolatore (Lettore CD/DVD, memoria aggiuntiva, Masterizzatore, ecc.).
tutte queste componenti sono collegate tra loro mediante BUS.

BUS = canale di comunicazione gestito dalla CPU, si individua come estensione esterna
della linea di comunicazione tra la CPU e la memoria. Sui bus transitano dati, indirizzi e
segnali di controllo. Ci sono vari standard.
Ogni periferica viene vista dalla CPU come un elemento di memoria, dotato quindi di
indirizzi prefissati.

N.B. interfaccia necessaria per mettere in contatto due realtà distinte, la CPU e la Realtà.
N.B. bus lunghi non funzionano, servono altri collegamenti

EVOLUZIONE DELLA MACCHINA DI VON NEUMANN

Nella macchina di Von Neumann ci sono dei limiti intrinsecamente determinati, che ne
determinano un difetto:
DIFETTO = le azioni sono sequenziali e non sono sovrapponibili
Con l’evoluzione tecnologica aumenta la capacità di elaborazione, si hanno CPU sempre
più rapide, con una migliore gestione dei dati e capacità di indirizzamento maggiori, ma
non si possono avere dei miglioramenti radicali proprio a causa della stretta sequenzialità
delle operazioni gestite dalla CPU.
Esempi dei limiti della macchina di Von Neumann:

1) Due unità autonome, CPU e dispositivo I/O devono mettere in sequenza le proprie
attività, perché non possono colloquiare in parallelo con la memoria.
(immagine del colloquio CPU periferiche dei primi capitolo)
2) Ogni istruzione si compone di fasi sequenziali
3) Non ci sono meccanismi che possano anticipare le richieste della CPU in modo da
ricercare in memoria i dati necessari per averli già a disposizione, si hanno solo
accessi sequenziali.
4) Se un istruzione deve essere ripetuta, bisogna seguire le tre fasi in sequenza,
sprecando del tempo, dal momento che l’istruzione era già stata prelevata e tradotta.
QUINDI = La macchina di Von Neumann ha per limite intrinseco la mancanza di
parallelismo
Il nostro scopo sarà di determinare un modo per introdurre un certo livello di parallelismo.

Analizziamo quali sono le risorse coinvolte in ogni fase.

FETCH DECODE EXECUTE

Program counter Decoder ALU

Instruction register Accumulatore

Registro dei FLAG

Noto che in ogni fase non viene usata a pieno la CPU!

 PIPELINE

Sistema applicato alla Macchina di Von Neumann per introdurre un certo grado di
parallelismo nell’esecuzione delle istruzioni.
Abbiamo visto che per le periferiche questo difetto si può risolvere introducendo
dei canali di I/O che permettano il colloquio periferica-memoria senza l’intervento
della CPU. Qui la soluzione adottata è diversa.
Concetto chiave alla base della PIPELINE è quello della catena di montaggio e deriva
dall’aver osservato che le risorse della CPU coinvolte nelle tre fasi di esecuzioni di
un’istruzione sono diverse.
REQUISITI:
 Ogni istruzione esegue le tre fasi di fetch, decode, execute, e impiega risorse
esclusive (non ci sono risorse usate contemporaneamente; dati, ecc.)
 Le istruzioni devono avere tempi di pari durata per ogni singola fase, cioè
ogni istruzione deve essere fatta alla stessa maniera.

La pipeline consiste nel sovrapporre la fase di esecuzione dell’istruzione i-esima


con la fase di decodifica dell’istruzione (i+1)-esima, con la fase di fetch degli
operandi dell’istruzione (i+2)-esima, con la fase di fetch del codice operativo
dell’istruzione (i+3)-esima.

Anziché avere un ciclo di esecuzione normale e sequenziale del tipo:

Avremo un ciclo di questo tipo:

Se però si verifica un’operazione JUMP?

Nel caso in cui si effettui un’istruzioni di salto, il programma funziona, ma la


pipeline non permette di guadagnare tempo, poiché non si può sfruttare il lavoro
fatto in anticipo.
Se per esempio il programma in figura “ i “ al 4° stadio viene eseguito e prevede un
salto, tutte le caselle sotto la diagonale, che corrispondo ai programmi successivi a
diversi stadi di preparazione, non servono più, quindi la pipeline si svuota, per poi
riempirsi di nuove istruzioni date dal salto. Questo fa sì che non ci siano guadagni
di tempo, ma in ogni caso il programma funziona.

 PARALLELISMO

Possiamo definire il parallelismo in base a due flussi normalmente presenti in un


calcolatore:
1) flusso dei dati (Data Stream)
2) flusso delle istruzioni (Instruction Stream)

Per le differenze che intercorrono relativamente i due flussi, possiamo distinguere


diverse “macchine”, ciascuna delle quali costituisce un’evoluzione della macchina di
Von Neumann.
 SISD
Propriamente sta per “Single Instruction Single Data” e identifica la macchina
di Von Neumann classica, in cui si ha un unico flusso di dati e istruzioni.
Viene eseguita una sola istruzione per volta, in maniera sequenziale
(un’istruzione dopo l’altra). È presente un processore e una memoria. Siccome
il collegamento tra essi è unico può insorgere un problema, noto come il
“collo di bottiglia di Von Neumann”. Che può generare un rallentamento
generale.

 SIMD
Che sta per “Single Instruction, Multiple Data”. È una macchina in cui si ha
una sola unità di controllo ma più unita aritmetiche indipendenti, cioè sono
presenti molte ALU. Il ciclo di funzionamento, tipico per esempio delle GPU
(Graphic Processing Unit, CPU dedicate alla grafica), prevede che una singola
istruzione venga utilizzata per l’elaborazione contemporanea di molti dati.
Un problema di questa macchina è situato a livello progettuale, poiché
bisogna mettere molte architetture in parallelo e fare in modo che i dati
vengano gestiti tutti allo stesso modo, altrimenti si perdono i benefici di
questa macchina.

PE = processing element. Ogni unità di elaborazione della SIMD. Con memoria


privata e collegate (le PE) per scambiarsi informazioni.

 MISD
Che sta per “Multiple Instruction, Single Data”. È una macchina in cui si hanno
più unità di controllo e molte unità aritmetiche, ossia molte ALU (tante quante
le unità di controllo, ciascuna dotata di una sua memoria, ossia di registri). Il
ciclo di funzionamento prevede che fornito un dato su di esso vengano
eseguite più istruzioni diverse allo stesso tempo. Detta anche “architettura
Pipeline”, ma non sono la stessa cosa. Vengono eseguite istruzioni diverse
sullo stesso pacchetto di dati.

 MIMD
Sta per “Multiple Instruction, Multiple Data”. È una macchina che prevede la
replicazione dell’intera struttura della macchina di Von Neumann, si
ottengono così architetture multiprocessore. Ci sono più processori che
operano in parallelo in modo asincrono, cioè, ciascuno processore gestiste
dati e istruzioni diverse dagli altri. Si tratta di un calcolatore costituito da più
unità di controllo e di calcolo che operano in parallelo su dati diversi
eseguendo istruzioni diverse.

La prima architettura rappresenta un processo di elaborazione seriale, mentre le


altre architetture mostrano un processo di elaborazione parallela. Come segue…
Guardando la struttura delle macchine MIMD, architetture multiprocessore, è evidente che
è necessario collegare tra di loro i vari processori, e questo fa sì che in base al numero di
processori, cresca esponenzialmente il numero dei bus impiegati per interconnetterli.
Anziché connettere tutti i processori tra di loro posso realizzare un BUS COMUNE e tanti
BUS LOCALI a cui collego i vari dispositivi e tramite i quali questi dispositivi possono
scambiarsi informazioni.
Svantaggio = i vari processori possono entrare in concorrenza per le stesse risorse, e
questo spiega l’introduzione di semafori. (vedi fine argomento). Altro svantaggio è il collo
di bottiglia.
Vantaggio = la notevole semplicità di questa organizzazione.

N.B: SEMAFORI = sono nello specifico dei flag realizzati in modo indicare lo stato di lavoro
di un dispositivo. Assume due stati, lo stato SET (impegnato) e lo stato CLEAR (libero).
Quando un dispositivo accede a una risorsa/dispositivo (che trova nello stato CLEAR),
modifica il flag nello stato set, impedendo quindi l’utilizzo della risorsa ad alti processori
fino a lavoro terminato.

N.B: STALLO = situazione in cui due o più processi non possono portare a termine il
proprio lavoro perché ciascuno aspetta l’accesso di risorse destinate all’altro. Essi si
verificano se e solo se:
1) c’è competizione per risorse non condivisibili;
2) le risorse sono richieste su base parziale, cioè un processo, pur avendo ricevuto delle
risorse, ne chiede altre in un secondo momento;
3) una volta che una risorsa è stata assegnata a un processo non può essere recuperata
forzatamente.

SISTEMI OPERATIVI
Diamo una definizione intuitiva di Sistema operativo:
SISTEMA OPERATIVO = insieme di programmi che rendono facilmente disponibili
all’utente le potenzialità offerte dalla macchina.
[A livello pratico si tratta dell’insieme di tutte quelle componenti hardware e software che
rendono operativa una data macchina.]

Il sistema operativo si compone di una serie di programmi che permettono all’utilizzatore


di gestire in modo trasparente i dati, prescindendo dalla struttura hardware sottesa al
calcolatore. Possiamo considerarlo come una virtualizzazione dell’hardware, nel senso che
ne nasconde le caratteristiche per essere fruibile da tutti.
Le funzioni del sistema operativo sono varie:
- Gestione dei lavori e delle risorse
- Ausili per la messa a punto di programmi e per la gestione dei dati
- Funzioni di contabilità, sicurezza, recupero, ecc.
Il sistema operativo, che viene fornito dal costruttore della macchina a titolo non gratuito,
si compone di due parti:
1) KERNEL (detto anche Nucleo)
2) SOFTWARE DI BASE
Le analizziamo:
 KERNEL

È un programma che viene eseguito all’accensione della macchina (bootstrapping) e


svolge due funzioni:
 fornire ai processi in esecuzione sull'elaboratore un accesso sicuro e
controllato all'hardware.
(quindi controlla l’esecuzione dei programmi utente).
 ha anche la responsabilità di assegnare una porzione di tempo-macchina
(scheduling) e di accesso all'hardware a ciascun programma (multitasking).
(quindi amministra le risorse hardware nei sistemi multiutente).

Il kernel impiega del tempo della CPU che viene sottratto ai programmi utente
causando un
OVERHEAD = tutto ciò che in termini di tempo, risorse e spazio di memoria viene
sottratto all’utente.
Il kernel all’avvio del calcolatore viene infatti caricato in RAM.

 SOFTWARE DI BASE

È un insieme di programmi che servono a facilitare la creazione di programmi da


parte degli utenti della macchina. Possiamo dire che si tratta di un insieme di
programmi messi a disposizione degli utenti per svolgere le operazioni di base.
Vengono caricati in RAM solo se ne è richiesta da parte dell’utente l’esecuzione.
Viene usato per:
 Editare un file
 Compilare
 Duplicare un file
 Cancellare, visualizzare, trasferire un file
 Utilizzare le periferiche
 Colloquiare con altri utenti
 Utilizzare la rete locale
 Inviare/ricevere posta
 Giocare
 …

Possiamo quindi dire che il sistema operativo funge da interfacci tra l’utente e la macchina,
intesa come hardware. Quindi:
- L’hardware della macchina è trasparente all’utente
- Saper utilizzare la macchina, significa sapere utilizzare il suo sistema operativo
- Il sistema operativo non dipende dall’hardware. Macchine diverse per hardware
supportano lo stesso sistema operativo, che si presenta nello stesso modo all’utente.
Analizziamo i vari casi di sistema operativo, ciascuno dipendente da diversi fattori
(forniamo i casi in ordine cronologico, inoltre i sistemi operativi integrano funzioni per la
gestione delle reti di calcolatori).

 SISTEMI OPERATIVI DEDICATI

“1 utente alla volta che può eseguire un programma alla volta”


Primi sistemi operativi introdotti, con un nucleo molto semplice

 SISTEMI OPERATIVI PER GESTIONE A LOTTI (BATCH)

Per sfruttare al meglio la CPU un insieme di lavori/programmi vengono accorpati in


blocchi. I blocchi vengono poi caricati ed eseguiti. Questo comporta l’esecuzione in
sequenza di ogni lavoro senza interruzioni fino al termine. CPU sottoutilizzata
perché durante le operazioni di I/O deve adeguarsi ai tempi e alla bassa velocità
delle periferiche.
Questo sistema operativo non esiste più, ne esistono delle varianti. Nato per
eliminare i tempi morti tra programmi successivi di utenti diversi.

 MULTIPROGRAMMAZIONE

Vengono caricati più programmi in memoria contemporaneamente. Viene sfruttato


il metodo di colloquio CPU-periferiche mediante canali I/O (ricordiamo che la
presenza del canale fa sì che, su autorizzazione della CPU, la periferica possa
reperire/inviare informazioni in memoria senza che esse passino per la CPU), questo
fa sì che le operazioni di I/O di un programma sono sovrapposte temporalmente
all’esecuzione delle istruzioni di un altro programma.
Si compone di tre stadi: RUNNING, BLOCK, READY
 Quando il primo programma in esecuzione chiede un servizio di I/O si blocca
(BLOCK) in attesa del risultato. A quel punto parte il secondo programma che
rimane in esecuzioni sino a quando non richiederà un servizio di I/O. nel
frattempo il primo programma avrà ottenuto i risultati e sarà entrato nello
stato READY, pronto a riprendere l’esecuzione del programma. Se così non
fosse quando il secondo programma va in BLOCK, parte il terzo programma.
Il procedimento di passaggio nei tre stadi si ripete fino a programmi conclusi.
 N.B: SCHEDULING = il codice operativo mantiene una o più code di processi
(programmi in READY) che vengono gestite secondo una priorità che li viene
assegnata, detta scheduling.
Vantaggi = CPU ben sfruttata
Svantaggi = la multiprogrammazione non riesce a differenziare tra processi che
richiedono spesso l’uso di dispositivi I/O da quelli che richiedono l’uso della CPU
per lunghi periodi di tempo, questo fa sì che quando uno di questi programmi ultimi
programmi viene eseguito, occupa la CPU impedendo agli altri programmi di
riprendere il lavoro e il guadagno in termini di tempo viene perso.
 SISTEMI OPERATIVI INTERATTIVI (TIME SHARING)

Sono sistemi operativi che per certi versi assomigliano alla multiprogrammazione,
ma presentano delle caratteristiche diverse. Infatti nella memoria vengono caricati
più programmi contemporaneamente. Il sistema time sharing risolve il problema
della multiprogrammazione, ossia la mancanza di equità a livello del tempo di
lavoro della CPU concesso a ogni programma. Qui infatti il tempo di utilizzo della
CPU viene suddiviso dal sistema operativo in intervalli uguali. Così ogni processo
riceve a turno l’utilizzo della CPU per un intervallo di tempo fisso.
Questo permette di sfruttare al meglio le capacità della CPU, con vantaggi anche a
livello temporale.
Vantaggi = l’utente lavora al terminale, e ha l’impressione di avere la macchina a sua
completa disposizione. Questo è dovuto al fatto che ogni processo ottiene
ciclicamente l’utilizzo della CPU.

PROBLEMA = la transizione da uno stato all’altro (RUNNING/READY/BLOCKED) non


è istantanea. A livello di risorse quando un programma deve ripartire deve essere
modificato il contenuto del Program Counter, e quando si ferma deve salvare in
memoria le informazioni necessarie per partire (PC, Reg FLAG, Contenuto Registri).
Questo evento passa con il nome di SALVATAGGIO DEL CONTESTO. Questo vuol
dire che in ogni intervallo di tempo che io concedo al programma, una parte iniziale
del tempo servirà per ricaricare il contesto e una parte finale per salvare il contesto.
Sono cioè due intervalli di tempo irrinunciabili nei quali il tempo della CPU non è
dedicato agli utenti. Si genera così un OVERHEAD per la gestione della CPU per i
molti processi attivi.

Ricarica del Contesto nella CPU


Salvataggio del Contesto in Memoria

N.B: l’intero sistema operativo non viene messo in memoria, ruberebbe spazio e tempo
agli utenti
Confronto tra i sistemi operativi proposti:
Il TIMING, cioè la temporizzazione dei processi (l’assegnare a ogni processo un
tempo stabilito) è dato da un circuito che ogni unità di tempo manderà un segnale
di INTERRUPT alla CPU (Segnale digitale sul bus dei controlli), permettendo così il
susseguirsi dei programmi. È in sostanza un controllo gestito con l’interrupt.

 SISTEMI OPERATIVI REAL TIME

Soluzione di sistema operativo proposta nel caso l’interlocutore non sia umano, ma
sia una macchina o un’applicazione. Stiamo parlando di un interlocutore che non
può accettare una aleatorietà/casualità nei tempi di risposta o esecuzione. Sono
quindi sistemi operativi al servizio di una specifica applicazione che ha dei vincoli
nei tempi di risposta.
Il sistema operativo deve garantire un tempo massimo entro il quale mandare in
esecuzione un programma a seguito di una richiesta in tal senso
1) Gestione di strumentazione
2) Controllo del processo
3) Gestione di allarme
4) Sistemi transazionali (banche, prenotazione)
Si ha un SISTEMA REAL TIME quando il tempo che passa dalla richiesta di
esecuzione di un processo al completamento della stessa e minore del tempo fissato.
 SISTEMI OPERATIVI PER SISTEMI CONCORRENTI

Sistema operativo applicato nel caso in cui siano presenti più CPU. Il sistema
operativo si prende carico di assegnare le diverse CPU ai processi, e si prende carico
di gestire le risorse in comune tra le varie CPU (memorie, bus, periferiche).
Il sistema operativo può essere svolto da più CPU, o da una sola CPU che sarà detta
MASTER, mentre le altre saranno dedicate ai programmi utente, e avranno compiti
differenti.

PROBLEMA (RISOLTO) = in sistemi di questo tipo (paralleli) si vuole avere una


maggiore affidabilità, tale da permettere di cambiare “schede” senza spegnere il
calcolatore, che deve sempre rimanere in funzione. Con tante CPU questo è possibile,
perché se una CPU si rompe, le altre continuano a funzionare.

COMPILAZIONE DI UN PROGRAMMA
La domanda principale a cui daremo una risposta è:

Come scrivere ed eseguire un Programma?

Appare evidente che non è possibile programmare fornendo alla macchina direttamente
stringhe di 0 e 1, dal momento che si creerebbero grandi difficoltà per il progettista. Per
creare un programma ci si affida al software di base, che è in grado di fornirci gli strumenti
per tale scopo.
Alcuni sistemi operativi presentano anche raffinati mezzi software per l’ausilio della
programmazione.
Per sviluppare un programma (software) servono dei passaggi (minimi, cioè sufficienti, a
cui poi possono aggiungersi altre fasi, ma non necessarie per avere la creazione di un
programma).

1) Editing dei testi dei programmi (detti sorgenti)


2) Compilazione dei sorgenti  oggetti
3) Linking dei vari oggetti (alcuni forniti dal compilatore)  programma eseguibile
4) Caricamento dell’ESEGUIBILE in memoria
5) Esecuzione del programma
6) Eventuale debugging

I FILE SORGENTE, FILE OGGETTO e FILE ESEGUIBILI vengono memorizzati su memoria a


supporto magnetico, caratterizzati da nome ed estensione ( .c per i sorgente; .o per gli
oggetto, niente per gli eseguibili). Ad essi viene anche associata la dimensione, i diritti di
accesso, ecc.
Il sistema operativo tratta tutti i file allo stesso modo, a prescindere dalla loro natura!
Possono quindi essere copiati, cancellati, spezzati, spostati, ecc.
Tenendo presenti le fasi di creazione (compilazione) di un Programma, analizziamo le
componenti che vengono utilizzate in ogni fase. Distinguiamo tre Macro fasi nella
creazione di un programma:
 SCRITTURA

La creazione di un programma nasce dalla sua stesura in un linguaggio di


programmazione, a fronte dell’elaborazione da parte di un
programmatore/progettista che ha elaborato gli algoritmi che lo compongono. La
scrittura di un programma prevede l’utilizzo di:
EDITOR = programmi che interagiscono direttamente con il programmatore
attraverso il terminale che permette di creare e modificare i TESTI (file in cui
compaiono solo caratteri ASCII). Con gli editor è possibile cancellare, inserire,
visualizzare, sostituire e copiare caratteri. Alcuni editor, detti EDITOR GUIDATI
DALLA SINTASSI generano direttamente i costrutti corretti, per un determinato
linguaggio, con un unico comando, garantendo la correttezza sintattica del
programma in corso di stesura.

Si generano così i PROGRAMMI SORGENTE (o file sorgente =file di testo che


contiene una serie di istruzioni scritte in un linguaggio di programmazione), ossia
programmi scritti in un linguaggio di programmazione.
Essi comprendono al loro interno il CODICE SORGENTE = testo di un algoritmo di
un programma scritto in un linguaggio di programmazione da parte di un
programmatore in fase di programmazione.

 TRADUZIONE

In questa fase il programma sorgente deve essere tradotto nell’unico linguaggio


comprensibile alla macchina, ossia in codice binario. Questa fase è la più importante,
perché si articola in fasi diverse. Non basta infatti che il programma, le istruzioni,
vengano tradotte in modo diretto, ma è necessario identificare le varie parti di
un’istruzione, la loro funzione. Distinguiamo tre tipologie di traduzione, dipendenti
da diversi fattori in primo luogo tecnici, mediante l’utilizzo di tre programmi
differenti.

N.B: i programmi che risultano alla fine del processo di traduzione non sono ancora
eseguibili, seppur si trovano scritti in linguaggio macchina.

 ASSEMBLATORE

Software che trasforma le istruzioni del programma sorgente scritte in


ASSEMBLY LANGUAGE in linguaggio macchina (binario). Svolge la funzione di
compilatore per il linguaggio di programmazione assembly. In genere è usato
per linguaggi di programmazione di basso livello. Per questi linguaggi di
programmazione si ha una corrispondenza 1 a 1 fra STATEMENT (blocco di
istruzioni) del file sorgente e istruzioni eseguibili.
L’assemblatore in una prima fase effettua l’analisi delle istruzioni e crea la
tavola dei simboli, nella seconda fase produce il codice in linguaggio
macchina per il processore.
Si genera così il PROGRAMMA OGGETTO = ossia il programma scritto in
linguaggio macchina. Al suo interno sono compresi di CODICI OGGETTO =
ossia le traduzioni dei codici sorgente in linguaggio macchina.

Si parla anche di MACROASSEMBLATORI, che ammettono


MACROISTRUZIONI, ossia istruzioni a cui vengono fatti corrispondere più
blocchi di istruzioni in linguaggio Assembly.

 INTERPRETE

Applicato a Programmi Sorgente scritti in un linguaggio di programmazione


di alto livello, è un programma in grado di eseguire altri programmi
direttamente senza compilazione, cioè esegue le istruzioni nel linguaggio
dato, traducendole di volta in volta in linguaggio macchina.
Questo caso rientra quindi già nella fase di esecuzione, poiché si ha
un’alternanza di traduzione/esecuzione, che non prevede altre fasi
intermedie. Quindi l’interprete traduce ogni istruzione riportata nel file
sorgente e ne comanda l’esecuzione. Questo è possibile poiché esiste una
tabella di conversione 1:1 che a ogni comando del file sorgente associa un
comando comprensibile al calcolatore.

 COMPILATORE

Utilizzato per la maggior parte dei linguaggi di programmazione di alto


livello. È un programma che traduce una serie di istruzione scritte in un
linguaggio di programmazione (nel file sorgente, diremo quindi che traduce
il codice sorgente) in istruzioni scritte in un altro linguaggio, producendo così
il codice oggetto e di conseguenza i Programmi Oggetto.

Il compilatore prende in ingresso il codice sorgente, su cui esegue una serie


di operazioni per ottenere; in assenza di errori, il codice oggetto. In generale
i compilatori sono in grado di riconoscere alcune classi di errori presenti nel
programma e in alcuni casi sono in grado di suggerirne la correzione.
Esistono due stadi importanti in cui viene divisa la compilazione:
 FRONTE END

In questo stadio il compilatore traduce il codice sorgente in un codice


scritto in un linguaggio intermedio.

1) ANALISI LESSICALE

Il compilatore individua e scansiona tutti gli elementi base del


codice sorgente/linguaggio (i TOKEN = elementi minimi e non
ulteriormente divisibili di un linguaggio come le parole chiave,
operatori, costanti, variabili, ecc.). i Token identificati vengono poi
classificati (creazione TAVOLA DEI SIMBOLI) e quindi codificati,
ossia riscritti come una stringa di simboli.

2) ANALISI SINTATTICA

Svolta dal PARSER, prende in ingresso la sequenza di Token


elaborata al primo punto ed esegue il controllo sintattico. Il
controllo sintattico è basato sulla GRAMMATICA del linguaggio di
programmazione. lo scopo è quello di riconoscere la struttura
grammaticale del programma, ottenuto raggruppando le unità
lessicali in istruzioni e riconoscendo il ruolo di ogni componente.
Una volta riconosciuta la struttura viene generata una forma
intermedia che corrisponde alla struttura sintattica del programma
(chiamata ALBERO o MATRICE DI SINTASSI). Vengono inoltre create
delle tavole dei simboli con tutti gli identificatori.

3) ANALISI SEMANTICA

Si occupa di controllare il significato delle istruzioni presenti nel


codice di ingresso, vengono effettuati due controlli: la
COMPATIBILITA’ delle espressioni legate agli operatori; e la
CORRETTEZZA delle dichiarazioni degli identificatori.

N.B: le verifiche vengono fatte direttamente sull’albero di sintassi

4) GENERAZIONE DEL CODICE INTERMEDIO

Viene generato il codice intermedio a partire dall’albero di sintassi.

 BACK END

In questo stadio viene generato a partire dal codice intermedio il


codice oggetto.

1) OTTIMIZZAZIONE DEL CODICE INTERMEDIO

Il codice intermedio generato in precedenza può essere


ottimizzato, cioè si possono ottimizzare la dimensione del codice
prodotto e il relativo tempo di calcolo.
2) GENERAZIONE DEL CODICE TARGET

Viene generato il codice nella forma del LINGUAGGIO TARGET (vale


a dire il linguaggio di arrivo). Molto spesso il linguaggio target è il
linguaggio macchina.

PRECOMPILATORI = programmi che precedono la compilazione, operano una


traduzione da un codice sorgente in un altro per il quale esiste un
compilatore.
METACOMPILATORI = programmi che, a partire dalla Grammatica del
linguaggio, generano un compilatore compatibile con il linguaggio stesso.

N.B. Un compilatore fornisce una traduzione più significativa dell’interprete:


quest’ultimo traduce infatti parola per parole il codice sorgente, mandando di volta in volta
parti di programma in esecuzione. questo non assicura una correttezza completa del
codice stesso. Il compilatore invece fornisce una traduzione molto più affidabile per quanto
riguarda la correttezza generale dell’intero codice sorgente, anche se richiede più tempo.
Il processo poi di ottimizzazione (che rende più veloce e compatto un programma certo
compensa del tempo in precedenza riservato all’analisi del programma sorgente).

 ESECUZIONE

In questa fase finale si situano quelle operazioni che permettono al PROGRAMMA


OGGETTO di essere trasformato in un PROGRAMMA ESEGUIBILE dalla macchina e
quindi portato ad esecuzione.
Parliamo così di:

CODICE ESEGUIBIE = è il codice scritto in linguaggio macchina adatto ad essere


caricato dal sistema operativo, quindi pronto per l’esecuzione; ed è adatto
all’architettura hardware del processore che lo esegue.

Se valgono le due condizioni può iniziare l’esecuzione.


Per ottenere il programma eseguibile servono degli strumenti:

 LINKER

Programma che effettua il collegamento tra il programma oggetto e le


LIBRERIE DEL LINGUAGGIO necessarie per l’esecuzione del programma. È
quel programma che permette di unire in un file eseguibile più moduli
oggetto che sono stato compilati separatamente. Utile per unire il lavoro
svolto da più utenti per creare un progetto/programma multiutente,
inizialmente scomposto in sotto-parti. Utile anche per unite moduli creati in
linguaggi di programmazione diversi.
 LOADER

Programma che si occupa di trasferire in memoria il file eseguibile, caricare


nel Program Counter l’indirizzo della prima istruzione eseguibile, e dare
inizio all’esecuzione del programma.

DEBUGGER = programma che permette di controllare la correttezza dell’esecuzione


del file eseguibile ottenuto. Il controllo può essere fatto facendo procedere
l’esecuzione fino a un punto di arresto (BREAK_POINT) per poi procedere passo a
passo nell’esecuzione delle istruzioni. Per funzionare usa informazioni create dal
compilatore/assemblatore e dal Linker. Permette inoltre di leggere e modificare il
contenuto dei registri della CPU e della memoria.

LINGUAGGI DI PROGRAMMAZIONE

I linguaggi di programmazione, come si è già intuito nel capitolo precedente, sono diversi,
e si sono evoluti nel tempo, rispondendo fondamentalmente alla necessità di introdurre un
linguaggio sempre più intuitivo e dalle strutture per quanto possibile sempre più “naturali”
e vicine alla lingua parlata dai vari programmatori. Questa caratteristica è la determinante
della suddivisione dei linguaggi di programmazione in varie “generazioni”.

 PRIMA GENERAZIONE

Essenzialmente i linguaggi di programmazione di prima generazione coincidono con


i linguaggi macchina, ossia con il Linguaggio binario. Le istruzioni sono scritte
usando la codifica binaria e sono direttamente eseguibili dalla CPU.
Vantaggi = alta efficienza.
Svantaggi = molto difficile, pessima leggibilità con anche un’elevata facilità di errore.
Altro problema è la non “portabilità dei programmi”, ossia i programmi non sono in
generale eseguibili su CPU a cui è associato un diverso linguaggio.

Programmatore deve ragionare secondo i piccoli passi incrementali del linguaggio


macchina.

 SECONDA GENERAZIONE

Rientrano nella categoria che vede il suo capostipite nel “Linguaggio Assemblativo”.
Le istruzioni, scritte in linguaggio assembly, sono quelle eseguibili dalla CPU,
espresse sotto forma di simboli mnemonici di codici operativi e operandi. Le
variabili sono espresse mediante nomi. Necessitano di un traduttore di linguaggio
macchina, l’ASSEMBLATORE., e possono essere usate per definire macroistruzioni.
Vantaggi = alta efficienza
Svantaggi = scarsa leggibilità, programmazione abbastanza difficile, problema
legato alla “non portabilità dei programmi”, questo perché i programmi non sono
eseguibili su CPU a cui è associato un diverso linguaggio.

Programmatore è indotto ancora a ragionare secondo i piccoli passi incrementali del


linguaggio macchina.
 TERZA GENERAZIONE

Corrispondente al “Linguaggio di Alto Livello”. Le istruzioni esprimono operazioni


significative nella logica del programmatore, tuttavia non sono direttamente
eseguibili dalla CPU, necessitano infatti di un traduttore (INTERPRETE o
COMPILATORE). La traduzione trasforma un’istruzione in una sequenza di
istruzioni macchina.
Vantaggi = maggiore facilità d’uso grazie all’introduzione di costrutti logici,
“portabilità dei programmi” su tutti gli elaboratori che dispongono di un traduttore
per il linguaggio.
Svantaggi = efficienza ridotta rispetto ai programmi assemblativi (dipende dal
compilatore), ma possibilità di ottimizzazione.

Sono linguaggi che prescindono dalle caratteristiche specifiche della macchina, ne


sono indipendenti. I programmatori ragionano in termini più naturali, meno legati
ai piccoli passi incrementali del linguaggio macchina.

Ex: FORTRAN, COBOL

I linguaggi ad alto livello sono a loro volta suddivisi sin 4 categorie:

1) Linguaggi Procedurali
2) Linguaggi Funzionali
3) Linguaggi basati sulla Logica
4) Linguaggi orientati agli oggetti
Analizziamo il primo caso:
LINGUAGGI PROCEDURALI
A differenza delle altre classi di linguaggi elencate, sono basati sul modello computazionale
di Von Neumann, in cui un programma è visto come una sequenza di istruzioni tendente
principalmente a modificare il contenuto della memoria.
Vantaggi:
- Sono indipendenti dalla macchina
- I dati possono essere rappresentati con nomi simbolici
- Sintassi vicina al linguaggio naturale
- Sono basati su istruzioni e assegnazioni
- Permettono astrazioni sui dati (è possibile anche definire tipi di dati e operazioni
eseguibili sulle varie tipologie di dati).
- Permettono astrazioni sul controllo (l’ordine delle istruzioni è determinato dalle
strutture di controllo o da moduli);
- Permettono l’utilizzo di SOTTOPROGRAMMI = definizione di nuove istruzioni e
operazioni.
- Buona leggibilità.
Sono suddivisi in tre categorie =
a) D’uso generale (BASIC, C, C++, JAVA, FORTRAN, PASCAL, COBOL, PL1)
b) D’uso speciale (CHILL, SIMULA, APT, AED, SQL, …)
c) Per applicazioni web (HTML, PHP)

SOTTOPROGRAMMI
Come già accennato nei linguaggi procedurali, è possibile in un programma l’utilizzo di
diversi sottoprogrammi.
SOTTOPROGRAMMA = sequenza di istruzioni che vengono eseguite a seguito di una
chiamata (CALL)
Vantaggi:
1) Scrivere una sola volta un codice (testo di un algoritmo) che viene utilizzato più volte
in un programma; non è così necessario riscriverlo più volte, ma è sufficiente il
comando di CALL inserito nei punti in cui il sottoprogramma viene richiesto.
2) Creare programmi strutturati per raffinamenti successivi (più leggibili);
3) Utilizzare librerie preconfezionate (ovvero un insieme di sottoprogrammi già in
dotazione).
Un sottoprogramma è caratterizzato da due Parametri:

- Parametri Formali = l’insieme dei simboli che rappresentano i dati su cui il


programma opera (simboli specificati nella definizione del sottoprogramma).
- Parametri Attuali (o Effettivi) = l’insieme dei dati, corrispondenti ai simboli
sopracitati, su cui il programma effettivamente opera. (dati specificati nella
chiamata a sottoprogramma).
Ci sono poi sottoprogrammi:
- Aperti
- Chiusi

 MACROESPANSIONE (SOTTOPROGRAMMI APERTI)

Nell’esecuzione di un programma non è raro che un sottoprogramma debba essere


chiamato più volte. Quando si vuole raggiungere il sottoprogramma viene utilizzato
un comando di CALL. La CPU coinvolge lo Stack Pointer e lo Stack Pila, per poter
caricare il sottoprogramma richiesto e prima salvare il contesto di lavoro in atto.
Una volta caricato il sottoprogramma, eseguito e terminato, si ritorna al punto in cui
si era interrotto il lavoro, cioè nel punto in cui era avvenuto il richiamo.

Il meccanismo della MACROESPANSIONE prevede a sostituire i singoli richiami con


l’intero blocco di istruzioni che costituiscono il sottoprogramma, sostituendo i
parametri effettivi con quelli formali.

In questo modo l’esecuzione del programma risulta sempre sequenziale anche


quando ci sono richiami a sottoprogramma (chiamato MACRODEFINIZIONE,
mentre la sua chiamata è detta MACRORICHIAMO). Si riducono così la serie di
interazioni tra la CPU, lo Stack Pointer e lo Stack Pila.
Tecnica che vale anche quando i sottoprogrammi sono NIDIFICATI, ovvero quando
prevedono durante la loro esecuzione ulteriori richiami a sottoprogrammi differenti.
 SOTTOPROGRAMMI CHIUSI

Il sottoprogramma chiuso compare una sola volta con tutte le sue istruzioni, ma
viene adoperato nei punti del programma in cui viene “chiamato”, mediante
comando CALL.
Siamo quindi all’opposto della Macroespansione, e quindi in una modalità differente
delle gestioni dei sottoprogrammi.
Questo sistema prevede che sia possibile la nidificazione di sottoprogrammi,
concetto spiegato in precedenza. Alcuni linguaggi di programmazione ammettono
chiamate a sottoprogrammi ricorsive, cioè il sottoprogramma richiama sé stesso.

Problemi:

o Determinazione dell’indirizzo di rientro al programma Chiamante (cioè


determinazione dell’indirizzo di ritorno);
o Passaggio dei parametri in ingresso (da Chiamante a Chiamato) e di uscita (da
Chiamato a Chiamante).
Vediamo come avviene la chiamata e il ritorno a sottoprogramma
GESTIONE DELLE CHIAMATE
Quando un sottoprogramma viene chiamato, l’indirizzo di rientro, cioè quello
dell’istruzione successiva a quella che ha effettuato la chiamata (e presente già nel
PC al momento della chiamata) deve essere salvato nello STACK (gestito dalla logica
LIFO), e lo STACK POINTER punterà all’indirizzo della cella che lo contiene, essendo
l’ultimo dato inserito. Al termine del sottoprogramma viene letto dalla PILA l’ultimo
indirizzo salvato nello STACK (alla cui cella di memoria che lo contiene punta lo
STACK POINTER), esso viene prelevato e messo nel Program Counter. Così abbiamo
auto il ritorno.
La logica Lifo permette di gestire anche la nidificazione delle chiamate a
sottoprogrammi.

NOTE FINALI
Ci sono due filosofie nella progettazione delle CPU:
- RISC = “Reduced Instruction Set Computer”, progettata in modo che l’unità centrale
sia in grado di eseguire solo un insieme minimo di istruzioni macchina. Si ha così
un Computer veloce, efficiente e poco costoso da costruire. Si basa sull’idea che
nuove funzioni, oltre un certo punto, possono migliorare la praticità nell’utilizzo
della macchina, tuttavia senza aggiungere nulla alle sue capacità di base.

- CISC = “Complex Instruction Set Computer”, progettata per essere in grado di


eseguire istruzioni complesse, anche se molte tecnicamente ridondanti. A favore c’è
il fatto che una CPU CISC possa gestire la via via crescente complessità del software
moderno, riducendo il divario tra linguaggio macchina e linguaggio ad alto livello.

Iniziato il 06/02/2017 Finito l’ 11/02/2017


S.e. & o.

Potrebbero piacerti anche