Estratto del documento

Lezioni di teoria SO 1 (prima parte)

Lezione 1 e 2 - Richiami e introduzione

Cosa è un processore e interfaccia HW/SW

Instruction Set Architecture (ISA)

Il processore è una macchina sequenziale che esegue delle istruzioni residenti in memoria per manipolare dei dati a loro volta residenti in memoria. Un processore non esiste se non è attaccato ad una memoria (chiamata set di istruzioni). L’Instruction Set Architecture specifica delle caratteristiche del processore visibili al programmatore, definisce l’insieme, l’interfaccia tra hardware e software, e specifica la funzionalità del processore in termini di:

  • Dati gestiti (tipi di dati)
  • Registri interni destinati a contenere i dati da manipolare
  • Istruzioni che prelevano dalla memoria e manipolano questi dati
  • Istruzioni di "salto"
  • Modalità di funzionamento speciali
  • Istruzioni speciali

Un processore è l’esecutore di istruzioni del proprio Instruction Set. Tramite le istruzioni macchina è possibile eseguire algoritmi specificati in un linguaggio ad alto livello. Il processore può eseguire le istruzioni del proprio IS solo una volta che le stesse sono state convertite in formato binario (codice macchina). La trasformazione da una rappresentazione all'altra viene eseguita da dei SW di supporto, il compilatore e l'assembler.

Figura: Come funziona il processore? Si accende, genera un indirizzo di memoria per la memoria di istruzioni per eseguire una istruzione che è all’interno di quell’indirizzo. Carica tramite una Fetch l’istruzione (perché non le ha dentro) ogni volta che le serve. Una volta caricata, viene decodificata, e invia a Memoria Istruzioni l’istruzione da eseguire. Da dove vengono le istruzioni? Dal codice ad alto livello (C). Le istruzioni vengono prese dal compilatore e le trasforma in codice assembly. Questo codice viene passato all’assembler che poi lo passa alla memoria istruzioni, dopo aver convertito le istruzioni in codice macchina.

Fetch delle istruzioni

Allo scopo di eseguire un algoritmo il processore esegue delle istruzioni del proprio IS. All'istante 0 dell'esecuzione (quando lo accendo) le istruzioni che codificano il programma da eseguire risiedono nella memoria istruzioni. Per poter essere eseguita dal processore ciascuna istruzione deve essere caricata in un registro interno del processore (fetch dell'istruzione). Solitamente il registro destinato a contenere l'istruzione corrente (quindi da eseguire) è denominato Instruction Register (IR).

Il flusso di esecuzione delle istruzioni viene definito dalla dislocazione in memoria delle istruzioni stesse e dalla tecnica di fetch utilizzata. Il flusso normale di esecuzione (che non fa uso delle istruzioni dedicate che si occupano di modificare tale flusso) prevede l’esecuzione sequenziale delle istruzioni secondo l'ordine di salvataggio in memoria. Un registro interno del processore contiene l'indirizzo della locazione di memoria all'interno della quale è contenuta la prossima istruzione da eseguire e prende il nome di Program Counter (PC).

Ogni volta che viene caricata ed eseguita una istruzione che non preveda la modifica del flusso di esecuzione, il PC viene incrementato in automatico in modo che la prossima istruzione caricata sull'IR e quindi eseguita sia la successiva a quella attualmente eseguita (sequenza di esecuzione normale). La modifica del flusso di esecuzione sequenziale viene gestita dalle istruzioni di salto.

Tipologie di istruzioni

Le principali tipologie di istruzioni sono 3 (a cui vanno aggiunte istruzioni di tipo eterogeneo non classificabili in maniera sintetica):

  • Istruzioni di spostamento dati: si occupano di spostare i dati dalla memoria ai registri interni del processore e viceversa. Esistono inoltre istruzioni che spostano i dati fra registri interni e istruzioni che spostano i dati fra locazioni di memoria.
  • Istruzioni di manipolazione dati: si occupano di prelevare i dati da locazioni (di solito dai registri interni), di utilizzarli come operandi sorgente per delle operazioni logico/aritmetiche e di salvare il risultato in altre locazioni.
  • Istruzioni di modifica del flusso di esecuzione (salto): si occupano di modificare il contenuto del PC in modo da modificare il flusso di esecuzione definito dall'incremento automatico del PC stesso.

Come funziona un processore: linguaggio assembly

Prendiamo come esempio MIPS. L’ISA dei processori della famiglia MIPS è di tipo load/store: non è possibile operare direttamente sui dati residenti in memoria, ma è necessario prima copiarli nei registri interni tramite istruzioni dedicate. I registri interni visibili (solo per la gestione dei dati interi) del MIPS sono:

  • 32 registri general purpose a 32 bit; il registro zero contiene 0 e non può essere modificato.
  • Un registro PC a 32 bit, che contiene l’indirizzo della prossima istruzione da eseguire.
  • Load word (lw): carica su un registro interno un valore dalla memoria [Esempio: Scrivi nel contenuto del registro 3, il contenuto della locazione di memoria avente per indirizzo il valore ottenuto dalla somma tra il registro 2 e l’indirizzo 0x100].
  • Store word (sw): scrive in memoria il valore contenuto in un registro [Esempio: uguale a Load].
  • Add: somma del valore di due registri.
  • Addi: somma di un registro con una costante contenuta nell’istruzione.
  • Subtract (sub): sottrazione tra il valore di due registri.
  • And: and logico bit a bit del contenuto di due registri.
  • Or: or logico bit a bit del contenuto di due registri.
  • Set on less than (slt): scrive 1 sul registro destinazione se il primo operando è minore del secondo, zero altrimenti.
  • Branch on equal (beq): salto condizionato all'uguaglianza dei valori contenuti nei 2 registri confrontati.
  • Jump (j): salto incondizionato [Esempio: salta all’indirizzo label2].

Nell’esempio: PC=PC+4+imm. 4 perché ci sono 32 bit divisi in 4 byte (=bit), quindi per andare alla prossima istruzione devo aggiungere 32 bit, ovvero 4 byte. Ad ogni byte è associato un indirizzo.

Formato delle istruzioni

Le istruzioni sono a lunghezza fissa (32 bit), in tre possibili formati [I bit sono dati dal valore elevato 2. Es: 52=32 che sono reg].

  • Immediate: viene usato per le istruzioni di branch (beq). Serve per le operazioni immediate (load e store).
  • Reg Type: viene usato per le istruzioni aritmetiche (add e sub).
  • Jump: viene usato per le istruzioni di jump [target: indirizzo di memoria dove andare per il salto].

Opcode: dice quale è l’istruzione attuale.

Richiami di programmazione assembly

L’esecuzione ciclica (loop) viene gestita tramite l’utilizzo di un registro indice/contatore che:

  • Viene inizializzato all’esterno del loop in funzione del numero di iterazioni da eseguire.
  • Viene aggiornato ad ogni iterazione del loop.
  • Viene testato ad ogni iterazione del loop, il test che verifica la fine del ciclo ne interrompe l’esecuzione.

L’accesso agli elementi di un vettore con indice dipendente dall’indice del loop può essere gestita tramite un reg detto puntatore che:

  • Viene inizializzato all’esterno del loop.
  • Viene utilizzato ad ogni iterazione del loop per comporre l’indirizzo della locazione corrente.
  • Viene aggiornato ad ogni iterazione del loop. L’aggiornamento dipende dal numero di locazioni di memoria occupate da ciascun elemento del vettore.

Esempio 3: codifica assembly

Utilizzo dei registri (esempio 3):

  • $1 ha la funzione di registro accumulatore.
  • $2 ha la funzione di indice/contatore del loop.
  • $3 ha la funzione di puntatore all’elemento corrente del vettore.
  • $6 memorizza la costante usata per il test di fine ciclo.
  • $7 ha la funzione di buffer temporaneo.

La sequenza utilizzata è crescente, dall’elemento 1 all’elemento 7.

Esempio 4: utilizzo dei registri

È possibile utilizzare un solo registro che accorpi le funzionalità di registro indice/contatore per il test di fine ciclo e di registro puntatore. In questo caso l’inizializzazione e l’aggiornamento del registro, nonché il test di fine ciclo, vanno gestiti in funzione del fatto che la funzionalità di registro puntatore richiede l’accesso a dati che possono occupare più locazioni di memoria.

  • $1 ha la funzione di registro accumulatore.
  • $2 ha la funzione di indice del loop e anche di puntatore all’elemento corrente del vettore.
  • $3 ha la funzione di buffer temporaneo.
  • $4 memorizza la costante usata per aggiornare il registro indice-puntatore.

La sequenza utilizzata è stavolta decrescente, dall’elemento 7 all’elemento 1. (Spiegazione L2 min 1:08:00 circa).

Meccanismo di chiamata a subroutine

  • Utilizzo combinato delle istruzioni jl e jr.
  • Salvataggio e ripristino dei registri.
  • Convenzioni per il MIPS nella gestione dello stack da parte del compilatore.

Le subroutine utilizzano le stesse risorse quindi ogni volta che prende un processore, deve salvare lo stato e restituirlo come era ripristinandolo. Lo stato è dato da registri, quindi questi devono essere gli stessi. Infatti deve salvare i registri che esporta.

Meccanismo di chiamata di procedura

Un opportuno sottoinsieme delle istruzioni dell’IS MIPS viene utilizzato per supportare la chiamata di una procedura (funzione), ed una volta terminata la sua esecuzione, il ritorno alla istruzione successiva alla chiamata. Ogni volta che deve essere convertita in assembly una chiamata a funzione viene utilizzata una istruzione “jal label procedura” (jal = jump a link) che forza il salto all’indirizzo della prima istruzione della procedura, e simultaneamente salva quello dell’istruzione successiva nel registro $31.

Funziona però solo per un livello di annidamento. Ogni procedura deve terminare con una istruzione “jr $31” (jr = jump register) che forza il valore del PC all’indirizzo della istruzione successiva a quella di chiamata, cioè all’indirizzo salvato in $31. Per gestire la possibilità che una funzione ne chiami a sua volta un’altra, sovrascrivendo l’indirizzo di ritorno in $31, è necessario che questo venga salvato in memoria. È necessaria una convenzione che definisca come salvare in memoria i parametri passati alla procedura, i dati locali, ecc.

Gestione dello stack

Quando viene eseguita una funzione viene riservata ad essa una porzione dello stack, detta frame. La dimensione del frame è variabile e dipende dal numero di dati relativi alla funzione che è necessario scrivere in memoria (può essere anche nulla se non ci sono dati da memorizzare). A ciascuna funzione è associato un frame pointer. Le informazioni da memorizzare di ogni frame sono:

  • Parametri della funzione invocata oltre il quarto (i primi quattro parametri sono salvati nei registri da $4 a $7).
  • Indirizzo di ritorno.
  • Dati locali della funzione.
  • Registri temporanei che verranno sovrascritti durante l’esecuzione della funzione.

Gestione della memoria per i sistemi monoprogrammati in modalità reale

Utilizzo della memoria nei sistemi monoprogrammati in modalità reale

Il compilatore utilizza la memoria dividendola in diverse parti: stack, heap, sezione testo e sezione dati statici/dinamici.

  • Lo stack è la porzione di memoria gestita automaticamente dal processore, inizia a partire dalle locazioni con indirizzo più alto e ha una dimensione variabile in funzione dello spazio di cui ha bisogno il programma.
  • Lo heap è invece la zona di memoria gestita dinamicamente, con le funzioni malloc e calloc che allocano spazio dinamicamente (Dynamic data). Inizia dalle locazioni di memoria più basse e si riempie verso locazioni di indirizzo più elevato a partire da un certo indirizzo.
  • La parte della memoria di indirizzi più bassi, da zero in poi, viene utilizzata per le istruzioni e per il codice (text area).
  • La parte della memoria riservata (Reserved).

A partire dagli indirizzi di memoria più alti sta la funzione main, il compilatore alloca ricorsivamente lo spazio per le procedure allocando e disallocando zone di memoria. Ogni procedura ha a disposizione una zona di memoria privata definita frame di attivazione. Lo spazio dei frame di attivazione è lo stack.

Comunicazione processore-periferiche: memory mapping

Memory mapping

La comunicazione tra processore e periferica è implementata tramite accessi in lettura/scrittura (istruzioni standard load e store) a locazioni di memoria. La periferica è dotata di registri interni ai quali il processore può accedere in lettura/scrittura. A ciascun registro interno di ogni periferica è associato un indirizzo di memoria. Lo spazio di memoria dedicato alle periferiche deve essere costituito da indirizzi non utilizzati per la memoria.

  • Lettura: ogni qualvolta il processore necessita di acquisire un dato dall'esterno esegue una istruzione di load. L’indirizzo è quello del registro della periferica che si vuole leggere. Il dato viene copiato su uno dei registri interni per poter essere subito utilizzato o copiato in memoria.
  • Scrittura: ogni qualvolta il processore necessita di mandare un dato all’esterno esegue una istruzione di store. L’indirizzo è quello del registro della periferica sulla quale si vuole scrivere. Il dato viene copiato da uno dei registri interni sul registro.

Scrittura sulle periferiche

Scrittura sulle periferiche (L3 min 50:00 circa). Il processore (MIPS) ha una porta dati e una porta indirizzi. L’indirizzo mandato dal processore viene letto da tutte le periferiche. Ciascuna periferica scrivibile ha la propria porta dati in ingresso collegata al bus di uscita del processore ed è inoltre collegata alla porta indirizzi. È dotata di un decoder che abilita la scrittura su uno dei propri registri interni solo nel caso in cui sul bus indirizzi si presenti l’indirizzo associato a quel registro e che il segnale di scrittura sia attivo. Gli spazi degli indirizzi non devono essere sovrapposti. È importante Write Enable Signal, bit che distingue il caso in cui sia da fare lettura o scrittura.

Lettura dalle periferiche

Le periferiche da cui leggere hanno la porta dati in uscita collegata ad uno degli ingressi di un multiplexer. Il multiplexer è collegato in uscita con la porta dati in ingresso del processore, ed è controllato da un decoder che decodifica il bus indirizzi abilitando in uscita l’ingresso associato all’indirizzo decodificato. Ciascuna periferica è collegata alla porta indirizzi del processore. È dotata di un apposito decoder interno che manda in uscita il contenuto del proprio registro interno avente indirizzo uguale all’indirizzo in transito sul bus.

Generalizzazione

Una volta convenuto che qualunque tipo di dato fisico può essere modellato come un numero binario e quindi esistono dei dispositivi (sensori/trasduttori) in grado di operare la conversione. Una periferica di input può essere il mouse o il microfono. Una periferica di out può essere una stampante, un display.

Funzionalità avanzate del processore: interrupt e timers

Interrupt

L’esecuzione del PC si aggiorna automaticamente, oppure tramite istruzioni di salto nel caso di esecuzione condizionale o esecuzione di subroutines. L’esecuzione di pezzi codice dell’algoritmo in maniera completamente asincrona rispetto alla codifica si basa su un altro meccanismo: l’interrupt. Esiste un ingresso hardware dedicato del processore, ingresso di interrupt. Ogni qualvolta si presenta un determinato segnale in ingresso all’interrupt, l’esecuzione del programma corrente viene sospesa, e viene eseguito un segmento di codice (di un'altra zona) associato all’ingresso di interrupt, detto routine di interrupt, al termine del quale, viene ripresa l’esecuzione del programma principale esattamente dal punto in cui era stato interrotto. L’implementazione è basata sulla sovrascrittura e ripristino di PC.

Periferica timer

Le specifiche di temporizzazione legate alla gestione real-time della interazione con l’ambiente esterno, rendono spesso indispensabile l’utilizzo di meccanismi che consentano l’esecuzione di determinati task (acquisizione di ingressi, scritture in uscita...) in maniera asincrona (in subroutines è sincrona) rispetto al ciclo di esecuzione del programma. Il meccanismo per risolvere questo tipo di problematiche è l’interrupt. L’interrupt deve essere veloce per permettere il continuo dell’esecuzione del flusso.

Nel caso la gestione real time debba avvenire in frequenze e istanti di tempo prestabiliti, risulta indispensabile una periferica che comunichi al processore un segnale di sincronismo con una frequenza fissa, indipendente dall’esecuzione in corso. Una periferica che svolge questo ruolo è il timer, programmato via software in modo da generare un interrupt per il processore con una determinata frequenza. Si tratta in pratica di un contatore programmabile che conta i cicli di clock in ingresso generando un segnale ad ogni fine conteggio.

Esempio di timer: La figura è una periferica memory-mapped, dotata di un registro di stato leggibile e parzialmente scrivibile, con una uscita di interrupt. Il clock utilizzato per il conteggio non è il clock utilizzato per il resto del sistema (global clk), ma un altro segnale di clock inserito appositamente nel sistema (sample clk). Ha un porta indirizzi, porta dati, un interrupt in uscita, global clk, sample clk e reset.

A cosa serve il sistema operativo: multiprogrammazione e astrazione dall’hardware

Il sistema operativo

I servizi fondamentali offerti dai sistemi operativi ai processi sono:

  • Astrazione dall’hardware.
  • Gestione efficiente delle risorse.
Anteprima
Vedrai una selezione di 7 pagine su 26
Sistemi Operativi - Appunti Teoria Prima Parte Pag. 1 Sistemi Operativi - Appunti Teoria Prima Parte Pag. 2
Anteprima di 7 pagg. su 26.
Scarica il documento per vederlo tutto.
Sistemi Operativi - Appunti Teoria Prima Parte Pag. 6
Anteprima di 7 pagg. su 26.
Scarica il documento per vederlo tutto.
Sistemi Operativi - Appunti Teoria Prima Parte Pag. 11
Anteprima di 7 pagg. su 26.
Scarica il documento per vederlo tutto.
Sistemi Operativi - Appunti Teoria Prima Parte Pag. 16
Anteprima di 7 pagg. su 26.
Scarica il documento per vederlo tutto.
Sistemi Operativi - Appunti Teoria Prima Parte Pag. 21
Anteprima di 7 pagg. su 26.
Scarica il documento per vederlo tutto.
Sistemi Operativi - Appunti Teoria Prima Parte Pag. 26
1 su 26
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher jiustin di informazioni apprese con la frequenza delle lezioni di Sistemi operativi e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli Studi di Cagliari o del prof Carta Salvatore.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community