1 Introduzione
Dal momento che sto ristudiando le basi del linguaggio assembly e avendo ritrovato degli appunti risalenti ai tempi di quando facevo l'ITIS ho pensato di trascriverli per metterli a disposizione degli utenti del forum.
In questo caso gli appunti riguardano la descrizione in maniera basilare e sintetica dell'architettura dei processori Intel della serie 8086/8088.
In questo caso gli appunti riguardano la descrizione in maniera basilare e sintetica dell'architettura dei processori Intel della serie 8086/8088.
2 Storia e origine dell'8086
Da Wikipedia:L'Intel 8086 (chiamato anche iAPx86 durante i primi anni ottanta) è un microprocessore a 16 bit progettato da Intel nel 1978, che diede origine all'architettura x86.
L'8086 è un processore di terza generazione, l'architettura si basa sui modelli precedenti 8080 e 8085 con la differenza di avere registri a 16bit che vedremo più avanti.
L'architettura a 16 bit, molto più complessa dei modelli precedenti, richiese all'epoca un aumento notevole del numero di transistor usati per realizzare la CPU, si passò dai 6.000 transistor dell'8080 ai 29.000 dell'8086.
Nel 1979 fu poi presentato l'8088 che si basava sull'architettura dell'8086, il formato delle istruzioni era identico ma aveva registri a 8bit e divenne lo standard commerciale dei PC dell'epoca.
L'architettura a 16 bit, molto più complessa dei modelli precedenti, richiese all'epoca un aumento notevole del numero di transistor usati per realizzare la CPU, si passò dai 6.000 transistor dell'8080 ai 29.000 dell'8086.
Nel 1979 fu poi presentato l'8088 che si basava sull'architettura dell'8086, il formato delle istruzioni era identico ma aveva registri a 8bit e divenne lo standard commerciale dei PC dell'epoca.
3 Caratterstiche salienti
Entrambi avevano l'address bus a 20bit capace di indirizzare 1Mbyte di memoria.Quando si parla di 8bit e 16bit si fa riferimento alla dimensione del data bus, infatti l'8088 aveva un data bus a 8bit contro i 16 dell'8086
Tabella comparativa con i processori successivi:
Caratteristiche | 8086/8088 | 80286 | Pentium |
---|---|---|---|
Address bus | 20 bit | 24 bit | 32 bit |
Data bus | 16 / 8 bit | 16 bit | 64 bit |
Indirizzamento | 1 MB | 16MB - 1GB Virtual | 4GB - 64TB Virtual |
Registri | 16 bit | 16 bit | 32 bit |
Piedini | 40 | 68 | 267 |
Compatibilità del software (assembler):
Intel
8086/8088 → 80286 → 80386 → 80486 → Pentium → ...
Motorola
68000 → 68020 → 68030 → 68040 -X-> PowerPC (non più compatibile)
4 Memoria Principale
- 1MB di memoria: 2²º = 1.048.576 locazioni di memoria di 8bit
- Il primo Byte ha indirizzo 0
- L'ultimo Byte ha indirizzo FFFFFH
5 Esecuzione di un programma
- Il programma è caricato in memoria centrale
- Si compone di due parti fondamentali: Istruzioni ("codice") e dati
- Il microprocessore legge ed esegue l'istruzione successiva in memoria, e così via in sequenza
- Alcune istruzioni particolari, dette di trasferimento di controllo ("salti", chiamate a procedure, interrupt, ...) modificano arbitrariamente l'indirizzo da cui è letta la successiva istruzione
- Ogni istruzione può o meno fare riferimento a un dato (o più dati) in memoria; in tal caso, viene calcolato l'indirizzo del dato ed eseguita un'operazione di lettura e/o scrittura all'indirizzo di memoria
6 Il microprocessore o CPU
La CPU è costituita da due blocchi funzionali:- Execution Unit (EU):
- Esegue le istruzioni (fase di execute)
- Il Bus Interface Unit (BIU):
- Rintraccia le istruzioni (fase di fetch)
- Legge gli operandi
- Scrive i risultati
6.1 Execution Unit
- Esegue le istruzioni
- Fornisce dati e indirizzi al BIU
- Modifica registri generali e registro flag
ALU, registri e bus interno a 16bit (8086/8088)
L'EU non ha connesioni dirette con il bus di sistema, cioè con il "mondo esterno".
Quando L'EU deve eseguire una nuova istruzione, la ottiene dalla coda gestita dal BIU e se la coda è vuota si pone in attesa.
Quando un'istruzione richiede di accedere alla memoria o a un device periferico, l'EU richiede al BIU di ottenere o memorizzare il dato.
Gli indirizzi manipolati dall'EU sono di 16bit.
Il BIU effettua le operazioni che permettono di accedere all'intero spazio di memoria disponibile.
L'EU non ha connesioni dirette con il bus di sistema, cioè con il "mondo esterno".
Quando L'EU deve eseguire una nuova istruzione, la ottiene dalla coda gestita dal BIU e se la coda è vuota si pone in attesa.
Quando un'istruzione richiede di accedere alla memoria o a un device periferico, l'EU richiede al BIU di ottenere o memorizzare il dato.
Gli indirizzi manipolati dall'EU sono di 16bit.
Il BIU effettua le operazioni che permettono di accedere all'intero spazio di memoria disponibile.
6.2 Bus Interface Unit
Il BIU esegue tutte le richieste dell'EU che coinvolgono il mondo esterno (e quindi il bus di sistema), cioè i trasferimenti di dati tra la CPU e la memoria o i dispositivi I/O- Calcola gli indirizzi reali a 20 bit sommando, in un sommatore dedicato, l'indirzzo del segmento e l'offset (entrambi a 16 bit)
- Esegue il trasferimento dei dati da e verso l'EU
- Carica le istruzioni nella coda delle istruzioni (prefetch)
Le istruzioni caricate dal BIU nella coda sono quelle che seguono l'istruzione correntemente in esecuzione nell'EU.
Se l'EU esegue un istruzione di salto, il BIU svuota la coda e comincia a riempirla di nuovo a partire dal nuovo indirizzo; in questo caso l'EU deve aspettare che la BIU abbia acquisito la nuova istruzione da eseguire.
Se l'EU esegue un istruzione di salto, il BIU svuota la coda e comincia a riempirla di nuovo a partire dal nuovo indirizzo; in questo caso l'EU deve aspettare che la BIU abbia acquisito la nuova istruzione da eseguire.
7 Registri Generali
- Data register: AX, BX, CX, DX
- Pointer register: SP, BP
- Index register: DI, SI
Registri a 16 bit (es. AX)
Registri a 8 bit (es. AH e AL - AHigh e ALow)
Per approfondire l'argomento registri e programmazione assembly consiglio questa guida di @DispatchCode
8 Mancanza di Ortogonalità
Ortogonalità: possibilità per le istruzioni di utilizzare uno qualsiasi dei registri come operando.
Esistono:L'8086 manca di ortogonalità
istruzioni che utilizzano i registri generali in modo implicito
ad esempio: le istruzioni che agiscono sullo stack coinvolgono sempre, in modo implicito, il registro SP
istruzioni che funzionano solo con particolari registri generali
ad esempio: l'istruzione per la lettura (scrittura) di un byte da una porta di I/O ha sempre il formato:
Codice:
IN AL, #porta
OUT #porta, AL
9 Registri di segmento
Lo spazio di memoria indirizzabile dalla CPU è diviso in segmenti logici massimo di 64kb.La CPU può accedere direttamente a 4 segmenti per volta, massimo 256kb.
Quattro registri di segmento puntano ai quattro segmenti correntemente attivi:
CS (Code segment) punta al segmento codice corrente:
Il segmento da cui vengono ottenute le istruzioni da eseguire.
SS (Stack segment) punta al segmento contenente lo stack corrente
DS (Data segment) punta al segmento dati corrente:
In genere tale segmento contiene variabili di programma
ES (Extra segment) punta la segmento extra corrente:
In genere anche questo segmento viene utilizzato per memorizzare dati.
10 Segmentazione fisica della memoria
Lo spazio di memoria viene visto come un gruppo di segmenti.
Ogni segmento:
- è un'unità logica di memoria indipendente, indirizzabile separatamente dalle altre unità
- Inizia a un indirizzo di memoria multiplo di 16
- è costituito da locazioni contigue di memoria
- è al massimo di 64kb
I segmenti si dicono allineati ai 16 byte (o allineati al paragrafo)
Ogni segmento è identificabile univocamente dai 16bit più significativi del suo indirizzo di partenza in memoria:
indirizzo fisico 220h
indirizzo di segmento 22h
Ogni segmento è identificabile univocamente dai 16bit più significativi del suo indirizzo di partenza in memoria:
indirizzo fisico 220h
indirizzo di segmento 22h
I quattro registri segmento puntano ai quattro segmenti correntemente utilizzabili.
Ogni programma in esecuzione può accedere direttamente a:
- 64kb di codice - CS
- 64kb di stack - SS
- 128kb di dati - DS e ES
I segmenti possono essere comunque disposti in memoria, ad esempio:
- Contigui
- Disgiunti
- Sovrapposti parzialmente
- Sovrapposti totalmente
Una locazione della memoria fisica può essere contenuta in più segmenti.
11 Instruction Pointer
- Registro a 16 bit IP
- Viene gestito dal BIU
- Contiene, in ogni istante, l'offset (cioè la distanza in byte) dell'istruzione successiva dall'inizio del segmento codice corrente (CS)
Il program counter classico coincide con CS : IP
12 Registro Flag
Registro a 16bit contenente:6 flag di stato
3 flag di controllo
I rimanenti bit non sono utilizzati.Flag: | OF | DF | IF | TF | SF | ZF | AF | PF | CF | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Bit no: | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
I flag di stato vengono modificati dall'Execution Unit in base al risultato delle operazioni logiche e aritmetiche.
Esiste un gruppo di istruzioni che permette al programma di controllare il contenuto di tali flag a fini decisionali.
CF | (Carry Flag, flag di Riporto) viene forzato a 1 se una somma/sottrazione ha prodotto riporto/prestito |
PF | (Parity Flag, flag di Parità) viene forzato a 1 se il risultato di un'operazione contiene un numero pari di 1 |
AF | (Auxiliary Flag, flag di Riporto Ausiliario) viene forzato a 1 se un'operazione ha prodotto riporto tra il primo (bit0÷bit3) e il secondo nibble (bit4÷bit7) |
ZF | (Zero Flag, flag di Zero) viene forzato a 1 se un'operazione ha dato risultato nullo; |
SF | (Sign Flag, flag di Segno) viene forzato al valore corrente del bit più significativo del risultato di un'operazione; come è noto nei numeri con segno 0 significa positivo e 1 significa negativo |
OF | (Overflow Flag, flag di Overflow) viene forzat a 1 se un'operazione ha prodotto trabocco, cioè ha superato il numero massimo per il registro coinvolto (256=100H a 8bit, 65536=10000H a 16bit, ecc) |
I flag di controllo possono essere settati o azzerati dal programma al fine di modificare il comportamento della CPU.
TF | (Trap Flag, flag di Cattura) molto utile perchè, se forzato a 1 (di solito con INT 03H) blocca nel punto predeterminato l'esecuzione di un programma in ambiente Debug; si presta dunque alla grande per l'esecuzione passo-passo (single-step) dei programmi |
IF | (Interrupt Flag, flag d'Interruzione Mascherabile) se forzato a 0 consente di disabilitare (mascherare) la possibile interruzione da parte di uno dei dispositivi abilitati a ciò; può essere controllato da software con STI (che lo forza a 1) o CLI (che lo forza a 0) |
DF | (Direction Flag, flag di Direzione) indispensabile nella gestione delle stringhe (MOVS , STOS o LODS) per stabilire se i registri indice coinvolti (DI o SI) devono essere incrementati (DF=0) o decrementati (DF=1); può essere controllato da software con STD (che lo forza a 1) o CLD (che lo forza a 0) |
13 Generazione dell'indirizzo fisico
Un indirizzo fisico è un valore di 20 bit che identifica in modo univoco ogni byte dello spazio di memoria di 1Mbyte
Per trasferire dati tra la CPU e la memoria è necessario utilizzare gli indirizzi fisici
Per trasferire dati tra la CPU e la memoria è necessario utilizzare gli indirizzi fisici
I programmi utilizzano indirizzi formati da:
- indirizzo del segmento
- offset nel segmento
Il BIU converte la coppia segmento : offset in indirizzo fisicosegmento : offset
Ciò avviene moltiplicando l'indirizzo del segmento per 16 e sommando al risultato l'offset nel segmento.
Lo stesso indirizzo fisico può essere ottenuto con diverse coppie segmento : offset
L'indirizzo fisico 1000H può essere ottenuto:
con 100H : 0H
con F0H : 100H
con E0H : 200H
ecc...
Il BIU ottiene la coppia segmento : offset da traslare, in modi diversi
Le istruzioni da eseguire vengono ricavate dal segmento codice corrente, pertanto l'indirizzo fisico della successiva istruzione è dato da: CS:IP, cioè CS*16 + IP
N.B. moltiplicare per 16 significa aggiungere a destra del valore esadecimale del registro di segmento 4 bit di valore nullo (un nibble uguale a 0):
Indirizzo fisico (20 bit) = Registro di Segmento * 16 + Registro di Offset
Se CS=1234H e IP=0100H dall'indirizzo logico CS:IP si ricava l'indirizzo fisico:
CS*16 = 1234H*10H = 12340H
IP = 0100H
indirizzo fisico → 12340H + 0100H = 12440H
Le istruzioni che agiscono sullo stack utilizzano il segmento stack corrente:
- SS contiene l'indirizzo del segmento
- SP contiene l'offset del top dello stack
L'offset della variabile viene invece calcolato dall'EU e dipende dalla modalità di indirizzamento specificata nell'istruzione.
14 Stack
- Area di memoria gestita LIFO (Last In First Out) e può contenere i record di attivazione delle procedure
- Realizzato in memoria centrale
- Definito dai registri SS e SP
Condizione di stack overflow/underflow
Un solo stack è quello corrente:
- SS contiene l'indirizzo del segmento stack
- SP contiene l'offset del top dello stack
l'indirizzo di partenza dello stack (contenuto in SS) non è il bottom dello stack
Le istruzioni che operano sullo stack trasferiscono due byte per volta (una word)
Operazione di push:
- SP → SP - 2
- Scrittura di una word al nuovo top
- Lettura di una word dal top
- SP → SP + 2
15 Interrupt
Un interrupt (interruzione) è un evento che si verifica in momenti non prevedibili.
L'effetto è quello di trasferire il controllo a una nuova locazione di memoria, in cui è collocata una procedura, detta routine di servizio dell'interrupt.
Al termine della procedura, si rientra nel programma principale.
Gli interrupt possono essere:
L'effetto è quello di trasferire il controllo a una nuova locazione di memoria, in cui è collocata una procedura, detta routine di servizio dell'interrupt.
Al termine della procedura, si rientra nel programma principale.
Gli interrupt possono essere:
- Hardware
- Software
- Hanno origine dalla logica esterna
- Permettono di gestire eventi asincroni
- Si dividono in:
- mascherabili
- non mascherabili
Gli interrupt software:- Hanno origine dall'esecuzione del programma:
- Direttamente (per es. l'esecuzione di un'istruzione INT)
- Indirettamente - condizioni eccezionali (per es. una divisione per zero)
15.1 Gli interrupt nell'8086
Le locazioni da 0H a 3FFH contengono una tabella (Interrupt Vector Table) con 256 ingressi.
Ogni ingresso contiene due valori di 16 bit che forniscono l'indirizzo della routine di servizio dell'interrupt e che vengono caricati nei registri CS e IP quando l'interrupt viene accettato.
I primi cinque elementi della tabella sono dedicati a particolari tipi di interrupt predefiniti nell'8086.
I successivi 27 elementi sono riservati all'hardware del sistema di elaborazione e non devono essere utilizzati.
I rimanenti elementi (da 32 a 255) sono disponibili per le routine di servizio e del sistema operativo dell'utente.
Un programma può anche generare esplicitamente un interrupt di tipo n, mediante l'istruzione INT #interrupt (es INT 21h).
Ogni ingresso contiene due valori di 16 bit che forniscono l'indirizzo della routine di servizio dell'interrupt e che vengono caricati nei registri CS e IP quando l'interrupt viene accettato.
I primi cinque elementi della tabella sono dedicati a particolari tipi di interrupt predefiniti nell'8086.
I successivi 27 elementi sono riservati all'hardware del sistema di elaborazione e non devono essere utilizzati.
I rimanenti elementi (da 32 a 255) sono disponibili per le routine di servizio e del sistema operativo dell'utente.
Un programma può anche generare esplicitamente un interrupt di tipo n, mediante l'istruzione INT #interrupt (es INT 21h).
- Netta separazione di ambienti tra il programma e la procedura
- Trasferimento del controllo a routine attraverso indirizzi non noti al programma
Esempi:
- Interrupt 0 (Divide Error) - segnala un errore durante un operazione di divisione (ad es. divisione per zero)
- Interrupt 1 (Single Step) - un'istruzione dopo il settaggio di TF (permette di eseguire una singola istruzione all'interno di un programma - utilizzato dal debugger)
- Interrupt 2 (Non-Maskable Interrupt) - è l'interrupt hardware di priorità più alta e non è mascherabile - di norma, è riservato ad eventi importanti e urgenti (ad es. una caduta di tensione, un errore nella memoria, un errore sul bus di sistema)
- Interrupt 3 (One Byte Interrupt) - utilizzato dal debugger per i breakpoint
- Interrupt 4 (Interrupt on Overflow) - condizione dioverflow (OF = 1) e viene eseguita l'istruzione INTO; permette di gestire l'eventuale condizione di overflow
15.2 Servizio di un interrupt
A livello hardware:
- Viene eseguita un push dei registri flags, CS e IPper salvare la situazione corrente e poterla ripristinare al termine del servizio
- Vengono caricati i nuovi valori di CS e IP dalla tabella degli interrupt
- Vengono azzerati i flag TF (trap per single step) e IF (interrupt)
L'azzeramento di IF disabilita il riconoscimento di ulteriori interrupt hardware nella routine di servizio a meno che tale riconoscimento non venga riabilitato esplicitamente all'interno della routine di servizio stessa.
La routine di servizio deve terminare con un'istruzione IRET (Interrupt RETurn), al fine dirispristinare correttamente la situazione presente almomento in cui si è verificata l'interruzione.
La routine di servizio deve terminare con un'istruzione IRET (Interrupt RETurn), al fine dirispristinare correttamente la situazione presente almomento in cui si è verificata l'interruzione.
16 Conclusioni
Anche se l'argomento tratta di un processore ormai obsoleto spero che il materiale sia stato ugualmente di vostro gradimento e abbia chiarito il funzionamento basilare di un processore.Per eventuali errori o inesattezze vi prego di scriverlo nei commenti!