Cerca nel sito:
ricerca
avanzata

Frasi Celebri...

E' una sventura non essere amati; ma e' un affronto non esserlo pi?.

Marcel Proust 

Sondaggio:

Windows XP ?...

Un grande affare
Il Sistema Operativo migliore sul mercato
Bello, ma niente di eccezionale
L'ennesima fregatura Microsoft
Una ciofeca peggiore dei suoi predecessori
Preferisco non commentare...

visualizza risultati


 

Architettura dei processori Intel

Il primo microprocessore della famiglia x86 prodotto dalla Intel è l' 8088 che entrò in produzione nel Giugno del 1978 !!! L'8088 è un processore a 16 bit con un BUS esterno a 8 bit e con un clock da 4.77MHz (8-|).

Da allora se ne' fatta di strada (basti pensare al processore Pentium a 32 bit) ma per questo tutorial per capire a grandi linee l'architettura di un processore Intel farò riferimento all' 8086 (non preoccupatevi tutto quello che dirò vale anche per i nuovi processori).

Allora per cominciare diamo un'occhiata al disegno qui sotto che rappresenta la struttura interna di un 8086 :

Bus Dati
---------------------------------------------------------------
---------------------------------------------------------------
  ^      ^    |    ^     ^    ^   ^      |   ^  ^  ^    |
  |      |    |    |     |    | +----+   |   v  v  v    |
  |      |    |    |     |    | | AX |   |   BX CX DX   |
  v      v    |    v     |    | +----+   |              |
+----+ +----+ | +----+ +----+ |   |      |           +----+
| SI | | DI | | | SP | | IP | |   v      v           | IR |
+----+ +----+ | +----+ +----+ | ----    ----         +----+
  |      |    |    |     |    | \   \  /   /            |
  |      |    |    |     |    |  \   \/   /             |
  |      |    |    |     |    |   \ ALU  /  +----+   +-------+
  |      |    |    |     |    |    \----/-->|FLAG|-->|Control|
  |      |    |    |     |    |      |      +----+   +-------+
  |      |    |    |     |    +------+
  |      |    |    |     |
  v      v    v    v     v
---------------------------------------------------------------
---------------------------------------------------------------
Bus Indirizzi

Lo schema è abbastanza semplice ma analizziamolo nel dettaglio.
A sinistra ci sono i due registri indice SI (Source Index) e DI (Destination Index) che vengono utilizzati come puntatori rispettivamente a dati sorgente e a dati destinazione. Questi sono registri a 16 bit e possono essere utilizzati anche come registri di OFFSET (Vedremo piu' avanti di cosa si tratta).

Il registro SP e lo Stack Pointer (Puntatore allo Stack). Lo stack è un'area di memoria in cui si possono memorizzare dei dati da passare alle procedure. La sua struttura è di tipo LIFO (Last In First Out) cioè: l'ultimo inserito è il primo ad essere estratto.

Vediamo meglio come funziona con un esempio:
Supponiamo di chiamare una funzione che somma due numeri, il prototipo in C sarebbe

int Somma (int a,int b);

ebbene quando viene chiamata la procedura i due addendi vengono salvati nello stack tramite l'operazione che prende il nome di PUSH , quindi

          |______|
          |      |
          |______|
   SP --> |   b  |
          |______|
          |   a  |
          |______|

Ora la procedura preleverà i due numeri dallo Stack con l'operazione di POP (attenzione all'ordine in cui vengono prelevati: prima b poi a !!!) ne effettuerà la somma e riporrà il risultato nello Stack:

          |______|
   SP --> | ris  |
          |______|    ris = a + b

A questo punto il programma chiamante dovrà solo prelevare il risultato dallo stack.

In realtà quando si chiamo una procedura oltre ai parametri nello stack si salvano anche cose come ad esempio l'indirizzo della chiamata per poterci tornare una volta finita la procedura e altri registri necessari a ripristinare il flusso del programma. C'è da sottolineare che il contenuto dello Stack Pointer viene aggiornato automaticamente dalla CPU quando si eseguono le operazioni di PUSH e di POP e non andrebbe modificato manualmente a meno di sapere bene cosa si sta facendo!!

Il registro IP (Instruction Pointer) contiene l'indirizzo della prossima istruzione da eseguire e il registro IR (Instruction Register) tiene il codice dell'istruzione in esecuzione, insieme eseguono il fetch dell'istruzione da eseguire:

IR <- [[IP]] ; metto in IR il dato puntato dal contenuto di IP
IP <- [IP] + 1 ; incremento il contenuto di IP

Per chi non lo sapesse il fetch dell'istruzione consiste nel prelevamento e riconoscimento dell'istruzione da eseguire.

Tutti i microprocessori Intel sono strutturati come una catena di montaggio suddivisa in stadi successivi, la CPU legge i codici operativi (OPCODE) delle istruzioni qualche ciclo di clock prima della loro reale esecuzione e sfrutta questo intervallo per eseguire la decodifica (oltre a qualche altro calcolo accessorio). Le istruzioni lette vengono messe nella PREFETCH QUEUE formata appunto da tutte le istruzioni lette ma non ancora eseguite, la dimensione della coda influisce sulla velocità (+ grande => + veloce) anche se oltre un certo valore non si registra alcun miglioramento. Le dimensioni della Prefetch Queue di un 8088 erano di 4 byte, quella di un 486 è di 32 byte.

I registri IP e IR non sono direttamente accessibili dal programma, anche se IP può essere indirettamente modificato tramite istruzioni di salto.

Ci sono poi i registri General Purpose : AX, BX, CX, DX che possono essere usati dai nostri programmi per memorizzare dati, puntatori e risultati.

AX - E' un registro a 16 bit divisibile in due registri a 8 bit: AH, AL in questo modo

  ---------------------------------
  | | | | | | | | | | | | | | | | |
  ---------------------------------
  |_____AH_______||_____AL________|
 |_______________AX________________|

AX viene usato come destinazione nei calcoli matematici (viene chiamato accumulatore). Va notato che cambiando il valore di AH e/o AL viene anche modificato il valore di AX !!

BX - Come AX si divide in BH e BL può essere usato come registro di OFFSET o come registro indice.

CX - (CH/CL) 16 bit (8+8) viene spesso usato come contatore nei cicli, infatti l'istruzione LOOP (che vedremo piu' avanti) decrementa il valore di CX fino a quando è uguale a zero.

DX - (DH/DL) 16 bit (8+8) viene usato come contenitore per il resto nelle divisioni o nel caso di operazioni a 32 bit per contenere la parte alta del risultato. Inoltre viene usato come puntatore nelle operazioni di Input e Output.

Oltre a questi registri presenti nello schema ne esistono altri:

BP - (Base Pointer 16 bit) Viene usato come puntatore alla base dello stack.

IP - Instruction Pointer: punta alla prossima istruzione da eseguire Registri di Segmento:

CS - Code Segment: punta alla zona di memoria che contiene il codice, durante l'esecuzione del programma contiene la prossima istruzione da eseguire.

DS - Data Segment: punta alla zona di memoria adibita al contenimento dei dati.

ES - Extra Segment: lo dice il nome, può essere usato come registro di segmento ausiliario.

SS - Stack Segment: punta alla zona di memoria in cui risiede lo stack.Attenzione a "giocare" con questo segmento!!

Per processori 386 e superiori esistono altri due registri di segmento FS e GS che possono essere usati come supporto per le operazioni.

Esiste inoltre il registro di FLAG in cui vengono riportate alcune informazioni circa le istruzioni in svolgimento, la sua struttura è la seguente:

 +-------------------------------------+
 |11|10|F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
 +-------------------------------------+
  |  |  | | | | | | | | | | | | | | | +-- CF Carry Flag
  |  |  | | | | | | | | | | | | | | +---- 1
  |  |  | | | | | | | | | | | | | +------ PF Parity Flag
  |  |  | | | | | | | | | | | | +-------- 0
  |  |  | | | | | | | | | | | +---------- AF Auxiliary Flag
  |  |  | | | | | | | | | | +------------ 0
  |  |  | | | | | | | | | +-------------- ZF Zero Flag
  |  |  | | | | | | | | +---------------- SF Sign Flag
  |  |  | | | | | | | +------------------ TF Trap Flag
  |  |  | | | | | | +-------------------- IF Interrupt Flag
  |  |  | | | | | +---------------------- DF Direction Flag
  |  |  | | | | +------------------------ OF Overflow flag
  |  |  | | +---------------------------- IOPL I/O Pr. Level
  |  |  | +------------------------------ NT Nested Task Flag
  |  |  +-------------------------------- 0
  |  +----------------------------------- RF Resume Flag
  +-------------------------------------- VM Virtual Mode Flag

Così se ad esempio dopo una sottrazione matematica il risultato è zero il bit relativo allo Zero Flag (bit 6) viene settato a 1.

Nei processori 386 e superiori sono presenti registri a 32 bit (!)con le funzionalità di quelli visti essi sono : EAX, EBX, ECX, EDX, ESI, EDI, EBP, CR0,CR2, CR3, DR0, DR1, DR2, DR3, DR6, DR7, dove CR sta per Control Register e DR Debug Register. Dalla generazione 486 in poi sono stati aggiunti : TR3, TR4, TR5 (Test Register).


SEGMENTO e OFFSET

Vi prego di prestare molta attenzione a questo argomento che ritengo di cruciale importanza: il modo in cui la CPU vede ed accede alla memoria.

I progettisti dei processori 8088 e 8086 nati anni e anni fa non potevano prevedere (???) che la tecnologia arrivasse a costruire macchine dotate di decine di MegaByte di memoria e cosi si sono limitati a progettare una CPU che riuscisse ad indirizzare solo un misero MegaByte :-(

Per indirizzare 1Mb sono necessari 20 bit (220= 1Mb) e noi abbiamo a disposizione solo registri a 16 bit, e allora come facciamo? La soluzione adottata dai progettisti del'Intel è quella di adottare un indirizzo costituito da 2 parti: un SEGMENTO e un OFFSET di 16 bit ciascuno, che uniti nel giusto modo danno origine all'indirizzo effettivo. Vediamo un esempio.

L'indirizzo 21F2:C01E è nella forma SEGMENT:OFFSET (gli indirizzi vengono dati sempre in base esadecimale per facilitare i calcoli) dove il segmento vale 21F2 e l'offset C01E entrambi di 16 bit, quindi un totale di 32 bit che non sono tutti necessari per indirizzare un solo Mega di memoria, e qui sta il bello !!! L'indirizzo nella forma SEG:OFF viene "trattato" per dare origine al vero indirizzo cioè il segmento viene moltiplicato per 16 (10h) e il risultato viene sommato all'offset. Nell'esempio precedente:

  21F2 · 10 = 21F20 +
               C0E1 =
              ------
              2E001

Otteniamo così un indirizzo a 20 bit !! (Semplice vero: beh forse non tanto !). Spesso invece di moltiplicare il numero per 16 (10h) si effettua uno SHIFT a sinistra di 4 bit ma come vedremo è la stessa cosa.

Come abbiamo visto prima i registri dedicati a contenere il valore del segmento so CS, DS, ES e SS, sono registri a 16 bit ciò vuol dire che un segmento è lungo 64Kb.

Del Mega che si può indirizzare se ne può usare solo i primi 640Kb perchè i rimanenti sono occupati dalla memoria video della VGA (a partire da A000:0000) e dal BIOS e quindi non ce ne rimane molto !!!

Bene anche questa puntata è terminata abbiamo conosciuto alcuni elementi fondamentali che ci serviranno per scrivere programmi in Assembly. So che non vedete l'ora di scriverne uno ma dovete avere un po' di pazienza: per programmare in Assembly (non mi stancherò mai di ripeterlo) bisogna conoscere a fondo l'architettura del computer visto che è proprio quello che andiamo a programmare!!

Per conoscere meglio le architetture delle ultime generazioni di processori sul sito http://www.intel.com nella sezione developer ci sono svariati manuali scaricabili gratuitamente che spiegano dettagliatamente il funzionamento dei Pentium e dei Pentium II nonchè di tutti gli altri processori Intel.

 

successivo
–«  INDICE  »–

 

 

 

 
Powered by paper&pencil (carta&matita ) - Copyright © 2001-2022 Cataldo Sasso