Preservare il valore dalla memoria al registro
Per preservare il valore letto dalla memoria e salvato nel registro utilizzo l'estensione del segno. Facendo ciò non cambio il significato del numero ma semplicemente estendo la sua rappresentazione da 1 byte a 4 byte.
Importante
Ho due tipi di istruzioni per Load Byte:
- Load Byte ← tratto il numero con segno. Eseguo l'estensione del segno.
- Load Byte unsigned ← tratto il numero senza segno, riempio i 3 byte restanti con soli zeri.
Nota
I caratteri ASCII non hanno segno! Questo problema del riempimento lo ho solo con le istruzioni di Load e non le ho nel caso di istruzioni di Store.
Load (memoria 1 Byte) → (registro 4 Byte)
Store (registro 4 Byte) → (memoria 1 Byte)
⇑ Posseggono solo il byte meno significativo
Esempio: Programma per copiare una stringa
void strcpy(char x[], char y[]) {
int i = 0;
while ((x[i] = y[i]) != 0)
i = i + 1;
}
Nota
Indirizzo stringa x = $a0
Indirizzo y = $a1
i = $a0
Estensione del segno per conservare il valore
PER PRESERVARE IL VALORE LETTO DALLA MEMORIA E SALVATO NEL REGISTRO UTILIZZO L'ESTENSIONE DEL SEGNO. FACENDO CIÒ NON CAMBIO IL SIGNIFICATO DEL NUMERO MA SEMPLICEMENTE ESTENDO LA SUA RAPPRESENTAZIONE DA 1 BYTE A 4 BYTE.
Importante
HO DUE TIPI DI ISTRUZIONI PER Load Byte:
- Load Byte ← TRATTO IL NUMERO CON SEGNO, ESEGUO L'ESTENSIONE DEL SEGNO.
- Load Byte unsigned ← TRATTO IL NUMERO SENZA SEGNO, RIEMPIO I 3 BYTE RESTANTI CON SOLO ZERI.
Nota
I CARATTERI ASCII NON HANNO SEGNO! QUESTO PROBLEMA DEL RIEMPIMENTO LO HO SOLO CON LE ISTRUZIONI DI Load E NON LE HO NEL CASO DI ISTRUZIONI DI Store.
Load (memoria 1 Byte) → (registro 4 Byte)
Store (registro 4 Byte) → (memoria 1 Byte)
⇑ POSESSO SOLO IL BYTE MENO SIGNIFICATIVO
Esempio: Programma per copiare una stringa
void strcpy(char X[], char Y[]) {
int i = 0;
while ((X[i] = Y[i]) != 0)
i = i + 1;
}
Nota
Indirizzo stringa X = $00
Indirizzo Y = $01
i = $00
Implementazione in Assembly
Strcpy:
addi $sp $sp -4
sw $t0 0($sp)
addi $s0 $zero 0
add $t1 $a1 $s0
L3:
lb $t2 0($t1)
add $t3 $s0 $s0
sb $t2 0($t3)
addi $s0 $s0 1
bne $t2 $zero L3
lw $t0 0($sp)
addi $sp $sp 4
jr $ra
Nota
Il carattere zero è il terminatore della stringa. Quando lo raggiungo ho terminato il programma.
$a1 va iniziare di i nello stack
Inizializzo i: 0
$t3 = ind Y[i]
$t2 = Y[i]
$t3 = ind X[i]
X[i] = $t2 = Y[i]
seguo le copie
Se $t2 ≠ 0 salto a L3 sennò proseguo
Ripristino dati originali
Torno al main program
Nota
In questo programma abbiamo un'imprecisione nell'istruzione 16, questo perché dovremmo usare l'istruzione lb. Questo perché nel codice ASCII la rappresentazione dei caratteri non ha segno.
Costanti e uso nelle istruzioni
Nell'80% dei casi le costanti vengono usate come operando. Per questo motivo dobbiamo trovare delle soluzioni pratiche per l'introduzione delle istruzioni che lavorano con le costanti. La soluzione adottata è quella di caricare all'interno dell'istruzione la costante.
Formato I
Il formato I prevede infatti di avere:
- Due operando
- Due registri
- Una costante per lo spostamento
Questo formato, detto anche formato idoneo per dati numerati, ci permette di inserire l'operando direttamente nell'istruzione. Costante (16 bit) rappresentata in complemento a 2.
Ricorda
Rop rs rt rd shamt funct Iop rs rt 16 bit address Jop 26 bit address
Esempio: Istruzioni immediate
- addi $29, $29, 4
- slti $8, $8, 10 ← confronto costante con registro
- andi $29, $29, 6 ← operazione di AND(&) con costante
- ori $29, $29, 4 ← operazione di OR(|) con costante
Osserva
Tutto questo è stato fatto affinché l'evento più frequente sia più veloce possibile. È la filosofia di progettazione del processore MIPS.
Nota
Se le costanti fossero in memoria i tempi sarebbero molto più lunghi!
Problema: Registro (32 bit) e Costante (16 bit)
Per le operazioni aritmetiche la soluzione adottata è quella dell'estensione del segno. Mentre per le operazioni logiche (or, and, ...) noi non abbiamo numeri con o senza segno ma abbiamo variabili booleane. In questo caso non svolgo l'estensione del segno ma riempio i restanti 16 bit con gli zeri.
Problema: se ho costanti > di 16 bit?
A tale scopo, per caricare una costante a 32 bit in un registro, ci viene in aiuto una nuova istruzione: lui (load upper immediate).
Esempio
lui $t0, 10101010101010101010101010101010 0000000000000000
Come modificare i 16 bit meno significativi?
Nota: Dobbiamo stare attenti a non usare quelle istruzioni che usano l'estensione del segno, perché ciò comprometterebbe il risultato finale.
addi $t0, $t0, 1010101010101010
Questo non va bene perché otterrei il seguente risultato:
1010101010101010 1111111111111010 + 0000000000000000 1010101010101010
Allora:
A tale scopo però possiamo usare le istruzioni logiche, le quali non fanno uso dell'estensione del segno.
ori $t0, $t0, 1010101010101010 0000000000000000 1010101010101010 1010101010101010 0000000000000000 1010101010101010 1010101010101010
OK!!!
Nota
NELLA SCRITTURA DELLE ISTRUZIONI NON POSSO USARE LA RAPPRESENTAZIONE BINARIA. POSSO USARE QUELLA DECIMALE, OPPURE QUELLA ESADECIMALE (LE DUE CIFRE DEL NUMERO ANTEPONGO 0X).
Osserva
A tale scopo possiamo usare una pseudo-istruzione che invoca al suo interno sia l'istruzione lui sia l'istruzione ori. Questa istruzione è detta: li (load immediate):
li $t0, 0X12345678 (32 bit) lui $t0, 0X1234 ori $t0, $t0, 0X5678
Traduzione pseudo-istruzione
$t0 <sub>REGISTRO DEDICATO ALL'ASSEMBLATORE PER LA TRADUZ...</sub>
Nota
li $t0, 0X1234 ori $t0, $zero, 0X1234
Se uso li con una costante a 16 bit, cosa succede?
L'assemblatore, prima di tradurre la pseudo-istruzione, controlla quanto occupa la costante. In questo caso siccome è di 16 bit non la traduce usando lui e ori, usa solo la ori.
li $t0, 0X12340000 lui $t0, 0X1234
ANCHE IN QUESTO CASO L'ASSEMBLATORE NON TRADUCE ALLA CICERA. SI ACCORGE CHE LA COSTANTE HA NEI 16 BIT MENO SIGNIFICATIVI SOLO ZERI. ALLORA USA LA SOLA LUI.
lui per caricare la costante nella parte alta del registro
Caricamento di un indirizzo in un registro
Noi possiamo caricare l'indirizzo in un registro utilizzando l'istruzione, appena vista load immediate (li), facendo ciò però dobbiamo specificare il valore dell'indirizzo (valore esteso a 4 byte). Risulterebbe più comodo se ci fosse un'istruzione che ci permettesse di caricare l'indirizzo nel registro per riferimento (come avviene nel costrutto case, quando vado a salvare l'indirizzo nelle etichette). A tale scopo ci viene incontro l'assemblatore che ci mette a disposizione l'istruzione di: load address (la) → la $t0, etchermo.
Questo è possibile poiché l'assemblatore usa la tavola dei simboli per ricavare l'indirizzo corrispondente all'etichetta.
Indirizzi nelle istruzioni di Branches e Jumps
- bne $t4, $t5, label
- beq $t4, $t5, label - Formato I (16 bit per indirizzo)
- j label - Formato J (26+2 bit per indirizzo)
Formato J
26 bit disponibili per l'indirizzo +2 bit - Poiché gli indirizzi sono multipli di 4 byte (1 word) allora i 2 bit meno significativi sono sempre due zeri
+4 bit - I 4 bit mancanti li eredito dal program counter composto cioè io considerino i bit del PC lasciando indietro i 4 bit più significativi! 32 bit
Formato I: (branches)
(-215, 215-1) rappresentazione.
| op (6bit) | rs (5bit) | rt (5bit) | 16 bit address |
Dentro i 16 bit dedicati all’indirizzo nel caso di istruzione di tipo branches verranno identificati il numero di istruzioni che separano la posizione attuale da quella identificata con l’etichetta.
| indirizzi in byte | → (-217, 217-1) intervallo di rappresentazione |
Nota
L’istruzione sono sempre composte da 32 bit → 4 Byte → 1 word. Gli indirizzi sono sempre multipli di 4 (nel caso di istruzioni).
→ (4, 235-4) → 2(-235, 235-1) | il processore lavora in byte e NON in numero di istruzioni!
Osserva
PC + offset = nuovo indirizzo | (32 bit) + (16+2 bit) → ? | Come mi comporto con i 16 bit mancanti?
In questo caso nei 16 bit mancanti: eseguo l’estensione del segno (portengo invariato il valore del numero).
Formato J
Identificando i 4 bit più significativi dal PC è come se avessimo partizionato la memoria in 24 = 16 macro blocchi Non ci possiamo muovere liberamente all’interno di un blocco di memoria grande 256 MB [228 byte].
Problema
Come faccio a fare salti con le istruzioni di branches maggiori dell'intervallo (-215, 215-1)?
Esempio
beq $t0, $t0, L1
Allora: Se L1 è compresa fra (-215, 215 - 1) istruzioni va tutto bene. Ma se L1 non appartenesse a questo range?
Questo problema viene risolto cambiando beq con bne.
bne $s0, $s3, New_L1
Dopo l'istruzione bne viene messa l'istruzione di jump all'etichetta L1 (quella di bne) questo perché con jump ho un range di salto molto più ampio.
Osserva
Il flusso logico rimane invariato, e grazie a jump ho a disposizione un range di salto non più di 16 bit ma di 26 bit.
Problema
Ma se neanche questi 26 bit bastano? Anche l'istruzione jump ha i suoi limiti, siccome essendo i 4 bit più significativi del PC, non possiamo fare salti che non appartengono allo stesso macro blocco.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
-
Appunti Calcolatori elettronici - parte seconda
-
Appunti Calcolatori elettronici - prima parte
-
Appunti del corso di Calcolatori elettronici
-
Appunti Calcolatori elettronici - terza parte