Mi è tornata nostalgia dei vecchi tempi, i tempi del famoso processore Intel 8088, il primo a 16 bit con BUS esterno a 8 bit e clock da 4.77Mhz !!

Ovviamente da quei tempi, avevo appena 3 anni, l’elettronica e l’informatica hanno fatto passi da gigante ma l’architettura di un processore tutto sommato non è variata moltissimo.

——————————————————————————–
——————————————————————————–
^ ^ | ^ ^ ^ ^ | ^ ^ ^ |
| | | | | | —– | 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
——————————————————————————–
——————————————————————————–

L’8086 era strutturato nel seguente modo :

  • 2 registri :  SI (Source Index) e DI (Destination Index) …usati come puntatori per i dati sorgenti e i dati destinazione. Sono registri a 16 bit utilizzati anche come OFFSET
  • registro SP (stack pointer) … un’area di memoria in cui si possono memorizzare dati da passare ad eventuali procedure. La sua struttura è di tipo LIFO (last in first out … ultimo dato inserito è il primo ad essere estratto)

Un esempio :

Supponiamo di dover sommare due numeri, in linguaggio C si scriverebbe

int somma (int a, int b);

In assembler quando richiamiamo la funzione per sommare, i due addendi vengono memorizzati nello stack per mezzo del comando PUSH

Per prelevare i numeri da sommare usiamo il comando POP che preleverà prima il valore di B e poi quello di A (B è stato l’ultimo inserito e quindi per via della struttura LIFO sarà anche il primo ad essere prelevato)

Avremo quindi una procedura che preleverà dallo stack i due numeri da sommare (B e poi A), li sommerà e poi li riporrà nello stack come risultato

SP = Risultato
Risultato = a +b

Avendo il risultato della somma dei due numeri presente nello stack dobbiamo solo richiamare tale valore (Risultato)

Quando richiamiamo una procedura, oltre ai parametri contenuti nello stack vengono salvati anche altri dati come ad esempio i registri e l’indirizzo della chiamata in modo tale da poterci tornare una volta terminata la procedura.

Il contenuto dello Stack Pointer viene comunque aggiornato dalla CPU quando si eseguono le operazioni PUSH e POP.

Il registro IP (Instruction Pointer) contiene invece l’indirizzo della prossima istruzione da eseguire ed il registro IR (Instruction Register) tiene a mente il codice dell’istruzione in esecuzione, assieme eseguono il cosidetto FETCH (prelievo) dell’istruzione da eseguire.

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

Le CPU Intel sono suddivise in stadi, le istruzioni da eseguire vengono espresse in codici operativi detti OPCODE che vengono letti alcuni cicli di clock prima della reale esecuzione in quanto è necessario che tali codici vengano decodificati e calcolati.

Le istruzioni che devono essere eseguite vengono prima lette ed inserite in una CODA chiamata PREFETCH QUEUE.
E’ importante notare che la dimensione della CODA (QUEUE) influisce sulla velocità di elaborazione delle istruzioni (più grande è la coda e maggiori istruzioni possono essere eseguite, quindi più veloce sarà l’esecuzione delle istruzioni). Nel caso del 8088 la coda consisteva di 4 byte mentre quella di un 486 era di 32 byte.

Anche si i registri IP ed IR non sono accessibili dal programma esistono registri di USO GENERALE chiamati AX, BX, CX, DX che possono invece essere usati per memorizzare dati, risultato e puntatori.

 

AX – E’ un registro a 16 bit divisibile in due registri a 8 bit : AH, AL in
questo modo (AH è il registro HIGH, AL il registro LOW). Se cambiamo i valori nel registro AH o AL automaticamente stiamo cambiando il valore del registro AX che li contiene.

AX viene usato come destinazione nei calcoli matematici ( viene chiamato
accumulatore).

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 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.
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. (Attenzione: non può essere modificato)

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 (Single Step)
| | | | | | | | +——————— IF Interrupt Flag
| | | | | | | +———————– DF Direction Flag
| | | | | | +————————- OF Overflow flag
| | | | +—————————– IOPL I/O Privil. Level(286+ only)
| | | +——————————- NT Nested Task Flag (286+ only)
| | +——————————— 0
| +———————————– RF Resume Flag (386+ only)
+————————————– VM Virtual Mode Flag (386+ only)
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.
Nei programmi posso comunque usare AX che viene considerato come registro a 16bit.
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 (2 ^ 20 = 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 !!!

 


0 commenti

Lascia un commento