Modalità di indirizzamento
Finora ci siamo preoccupati molto poco di come vengono interpretati i bit dei campi d’indirizzo per trovare gli operandi.
Indirizzamento immediato
Il modo più semplice con cui un’istruzione può specificare un operando è di contenere nel campo riservato al suo indirizzo, l’operando ( operando immediato ) stesso invece che un indirizzo.
La seguente figura mostra una possibile istruzione con un operando immediato ( 4 ) che viene messo in R1 :

Con questa modalità però si può lavorare solo con una costante alla volta.
Indirizzamento diretto
Un metodo per specificare l’operando in memoria è darne l'indirizzo completo. Se però da una parte il valore cambia, la locazione ( indirizzo ) non può cambiare. Per questa ragione l'indirizzamento diretto serve solo ad accedere a variabili globali, di cui l’indirizzo è noto in fase di compilazione.
Indirizzamento indiretto
L’indirizzo di memoria fornito punta all’indirizzo dell’operando.
Indirizzamento a registro ( diretto )
Questo indirizzamento è analogo all’indirizzamento diretto, ma si specifica un registro invece che la locazione di memoria dell'operando. È una modalità molto utilizzata siccome i registri sono veloci in accesso e hanno indirizzi brevi.
Indirizzamento a registro indiretto
L’indirizzo dell’operando non è contenuta nell’istruzione, ma il suo indirizzo ( puntatore ) è contenuto in un registro che viene specificato.
Per capire vediamo un esempio : supponiamo di avere un array A di 1024 interi e vogliamo calcolare la somma nel registro R1.
Possiamo usare :
R2per puntare all’indirizzo del primo elemento ( inizialmente )R3per puntare all’indirizzo immediatamente successivo all’ultimo elemento Inoltre possiamo osservare che se l’array è di 1024 interi ed ogni intero è grande 4 byte allora, per avere l’indirizzo immediatamente successivo all’ultimo elemento, basta prendere l’indirizzo del primo elemento (R2o#A) e sommare .

Quindi avremo il seguente codice assembly :
MOV R1,#0 // impostiamo R1 inzialmente a 0
MOV R2,#A
MOV R3,#A+4096
LOOP:
ADD R1,(R2) // indirizzamento registro indiretto
ADD R2,#4
CMP R2,R3
BLT LOOP // se R2 < R3 continua PS : questo linguaggio assembly non è ARM (simile), ma un assembly generale didattico per far capire.
In questo programma abbiamo usato diverse modalità di indirizzamento :

È possibile inoltre utilizzare un’altra maniera senza l’utilizzo di indirizzamento a registro indiretto :

L’idea fu di Von Neumann quando non esisteva l’accesso a registro indiretto, ma ora non si usa più.
Indirizzamento indicizzato
L’indirizzamento indicizzato combina :
- un registro che contiene un’indirizzo base (che cambia)
- un offset ( spiazzamento ) costante per trovare la posiziona esatta
Per mostrare il funzionamento vediamo un esempio : supponiamo di avere due array A e B contenenti ognuno 1024 word, e di voler calcolare A[i] AND B[i] per tutti gli elementi e poi fare OR dei risultati parziali, per verificare se esiste una coppia ( tutti e due diversi da 0).
Quindi fare una cosa del genere : (A[0] && B[0]) || (A[1] && B[1]) || ...
Possiamo utilizzare 4 registri :
R1: contiene il risultato degli ORR2: contiene l’indiceiper “scorrere” gli arrayAeBR3: contiene costante 4096, per controllare la fine dell’arrayR4: contiene il risultato degli AND
Avremo quindi il seguente codice assembly :
MOV R1,#0
MOV R2,#0
MOV R3,#4096
LOOP:
MOV R4,A(R2) // R4 = A[i]
AND R4,B(R2) // R4 = R4 AND B[i] = A[i] AND B[i]
OR R1,R4
ADD R2,#4 // i = i + 4
CMP R2,R3
BLT LOOP La modalità indicizzata è presente per esempio in MOV R4,A(R2), dove il registro R2 sommato all’indirizzo di A è la somma usata come riferimento in memoria. Inoltre sta roba viene fatta anche in C con i puntatori : array[i] = *(array + i) (sono la stessa cosa).
È importante capire che
Aè usato come offset eR2come registro.
Indirizzamento indicizzato esteso
Alcune macchine permettono di calcolare l’indirizzo di memoria sommando tra di loro il contenuto di due registri ( + offset opzionale ), dove :
- un registro memorizza la base
- un registro memorizza l’indice
Infatti questa modalità ci sarebbe stata utile nell’esempio precedente, dove potevamo inizializzare A con R5 e B con R6 e utilizzare questa modalità nel seguente modo :
...
...
LOOP:
MOV R4,(R2+R5)
AND R4,(R2+R6)
...
...Indirizzamento a stack
Coma già abbiamo visto, è molto consigliabile rendere le istruzioni macchina più corte possibili.
Infatti come abbiamo visto ci sono istruzioni che non specificano indirizzi, come l’istruzione IADD in Esempio di ISA - IJVM, che sono in associazione con uno stack.
Vedi in Notazione polacca inversa.
Modalità d’indirizzamento per istruzioni di salto
Finora abbiamo analizzato istruzioni che operano sui dati, ma anche le istruzioni di salto ( e le chiamate di procedura ) necessitano di una modalità di indirizzamento per la destinazione del "salto". Le modalità fatte fino ad ora funzionano quasi tutte anche per i salti.
Ortogonalità dei codici operativi e delle modalità d’indirizzamento
Da un punto di vista software, le istruzioni e gli indirizzamenti dovrebbero avere una struttura regolare, per fare in modo che i compilatori producano un buon codice.
Quando infatti tutte le modalità di indirizzamento sono utilizzabili con tutti i codici operativi si può dire che l’istruzione è ortogonale.
Per esempio consideriamo questi 3 formati di istruzione da 32-bit :

Vediamo perché sono ortogonali i formati :
- formato 1: può avere fino a 256 opcode e ogni istruzione avrà 2 registri sorgenti e 1 registro destinazione. Infatti tutte le istruzioni aritmetiche e logiche usano questo formato
- formato 2: se il bit messo a 0 nel formato, viene messo a 1, il formato 2 verrà utilizzato e l’ultimo registro diventa una costante da 13-bit
- formato 3: utilizzato per le istruzioni di salto
L’ortogonalità è proprio nel fatto che, l’istruzione
ADDper esempio, potrebbe usare il formato 1 o il formato secondo il metodo di indirizzamento usato.
Modalità di indirizzamento del Core i7
Abbiamo già visto in Formato delle istruzioni che il formato delle istruzioni del Core i7 è il seguente :

Questo formato NON è ortogonale, infatti abbiamo un formato di istruzioni irregolare e complesso e siccome una parte di queste istruzioni possono assumere significati diversi a seconda dell’opcode.
