Laboratorio di Architettura degli Elaboratori Dott. Massimo Tivoli Set di istruzioni del MIPS32: istruzioni aritmetiche e di trasferimento Istruzioni • (Alcune) Categorie di istruzioni in MIPS – Istruzioni aritmetico/logiche • Queste istruzioni effettuano operazioni aritmetico‐ logiche sui registri del processore – Istruzioni “Load and Store” • Queste istruzioni spostano dati fra la memoria e i registri generali del processore – Istruzioni decisionali • Queste istruzioni effettuano il confronto fra i valori contenuti nei registri Istruzioni Aritmetiche ● add a, b, c #a=b+c ● sub a, b, c #a=b-c – TRE operandi ● ● OPERATORE operando1, operando2, operando3 NOTE: – Ciascuna linea puo’ contenere solo una istruzione; – # viene usato per commenti ● add a, b, c # Questa istruzione esegue la somma a=b+c Istruzioni Aritmetiche • Note: – Tutte le istruzioni aritmetiche hanno esattamente tre operandi (numero fisso) per mantenere l’Hw semplice – L’hardware necessario per un numero variabile di operandi è più complesso di quello richiesto per un numero fisso di operandi ⇓ PRINCIPIO DI PROGETTO 1: semplicita’ e regolarita’ sono strettamente correlate – Ordine fissato (destinatario per primo) • OPERATORE operando1, operando2, operando3 ⇓ • operando1 = operando2 OPERATORE operando3 * Esercizio • Scrivere la seguente istruzione in assembler MIPS: a = (b+c) – (d‐f) + g add x, b, c sub y, d, f sub x, x, y add a, x, g • Quante operazioni aritmetiche ci vogliono per sommare/sottrarre/etc. n numeri? Registri (continua…) • Data una istruzione aritmetica: – Operandi = Registri – MIPS32 ha 32 registri, di uso generale, a 32 bit • Variabili ≠ Registro: – Variabili in un LP‐alto‐livello sono infinite – I registri nell’Hw sono finiti – In un LP‐alto‐livello le variabili posso far riferimento sia a registri che a locazioni di memoria che non sono registri (in modo trasparente al programmatore) • Un numero di registri elevato aumenterebbe la durata del ciclo di clock – i segnali elettrici devono coprire una distanza maggiore • Maggiore è il numero dei registri e maggiore è il numero di bit necessari per indirizzarli all’interno di una istruzione – ricordate sempre che per la macchina add x, b, c = 1000110010100000… PRINCIPIO DI PROGETTO 2: Minori sono le dimensioni, maggiore e’ la velocita’ Registri e loro uso • Notazione per l’assembler del MIPS32 – nome costituito da due caratteri preceduti dal carattere ‘$’ – $s0, $s1, … per i registri che corrispondono a variabili nei programmi scritti in un LP‐alto‐livello da compilare in linguaggio assembly per MIPS32 – $t0, $t1, … per i registri temporanei necessari alla compilazione di programmi in istruzioni MIPS32 • a = (b+c) – (d‐f) + g add $t0, $s0, $s1 sub $t1, $s2, $s3 sub $t0, $t0, $t1 add $s5, $t0, $s4 # il reg. temp. $t0 contiene il ris. di b+c (i.e., $s0+$s1) # il reg. temp. $t1 contiene il ris. di d‐f (i.e., $s2‐$s3) # il reg. temp. $t0 contiene il ris. di (b+c) – (d‐f) # il reg. $s5 contiene il ris. di (b+c) – (d‐f) + g (parte della) Architettura del MIPS32 MAR Abbiamo solo 32 registri… come facciamo a gestire strutture dati complesse (es. vettori)??? 32 Registri, ognuno a 32 bit Memoria R1 R32 MBR MEMORIA oppure cosa facciamo se 32 var. non mi bastano??? 32 bit R1 R2 … Rn ALU CONTROLLO CPU 32 registri Istruzioni di Trasferimento • lw $s1, 10($s2) # carica in $s1 l’undicesimo “valore” del vettore che inizia alla # locazione, in memoria, il cui indirizzo è il valore di $s2 – lw = Load word (si ricordi che 1 word = 32 bit per il MIPS32) • sw $s1, 100($s2) – ● sw = Store word NOTE e delucidazioni: – Memoria vista come un VETTORE – Le istruzioni aritmetiche richiedono che gli operandi siano memorizzati nei registri ● Istruzioni di “Trasferimento” – Indirizzo di base (e.g., $2,$3) + offset (e.g., 10,100) – Memoria indirizzata a singolo byte (vedi slides succ.) Attenzione • La memoria è indirizzata al singolo byte – la mem. è vista come una sequenza lineare di celle (o locazioni) da 8 bit = 1 byte (da 0x00000000 a 0xFFFFFFFF, fino a 4GB di mem. indirizzabili) MEM … mentre • • I registri sono indirizzati a 32 bit e un registro contiene un dato a 32 bit (= 4 byte = 4 locazioni) => l’indirizzo di una word, semanticamente valida, in memoria è sempre l’indirizzo, di una locazione, che è multiplo di 4 Vogliamo caricare il 3° elemento del vettore A: ovvero vogliamo prelevare il valore di A[2] (iniziamo a numerare gli elementi di un vettore da 0, cioè A[0] è il primo elemento del vettore) Cosa vuol dire?? 0x1000 000F 0x1000 000E 0x1000 000D 0x1000 000C 0x1000 000B 0x1000 000A 0x1000 0009 0x1000 0008 0x1000 0007 0x1000 0006 0x1000 0005 0x1000 0004 0x1000 0003 0x1000 0002 0x1000 0001 0x1000 0000 Word i+3 Word i+2 Word i+1 Word i 1 byte (8 bit) … Attenzione • Vogliamo caricare il 3° elemento (ovvero la 3° word) del vettore A: ovvero vogliamo prelevare il valore di A[2] dove MEM – A è memorizzato a partire dalla locazione 0x1000 0000 – supponiamo che $s2 contenga proprio il numero 0x10000000 A – lw $s1, 2($s2) – lw $s1, 8($s2) … Word i+3 Word i+2 A[2] – Indirizzo di base (a 32 bit) + offset (a 16 bit) Word i+1 – “Big end” e “Little end” Word i – Che succede quando il numero di variabili nel LP‐alto‐livello supera il numero di registri? • “Spilling” dei registri 1 byte (8 bit) … perchè 16 bit sarà chiaro più avanti nel corso 0x1000 000F 0x1000 000E 0x1000 000D 0x1000 000C 0x1000 000B 0x1000 000A 0x1000 0009 0x1000 0008 0x1000 0007 0x1000 0006 0x1000 0005 0x1000 0004 0x1000 0003 0x1000 0002 0x1000 0001 0x1000 0000 Little Endian e Big Endian (continua…) • Come viene rappresentata una word del MIPS32 (quindi un numero a 32 bit) in 4 byte di memoria? – 0001 0010 0011 0100 0101 0110 0111 1000 = 0x12345678 • Esistono due schemi: – Little Endian: memorizza a partire dalla "little end" (ovvero a partire dai bit meno significativi) della word • cioe’, 0111 1000 registro: 0x12 0x34 0x56 0x78 byte 3 byte 2 byte 1 byte 0 – Big Endian: memorizza a partire dalla "big end" (ovvero dai bit più significativi) della word • cioe’, 0001 0010 registro: • MIPS lavora in Big Endian 0x78 0x56 0x34 0x12 byte 3 byte 2 byte 1 byte 0 – Infatti, l’indirizzo di base 0x10000000, in memoria, viene specificato tramite il contenuto di un registro a 32 bit, $s2 nell’esempio precedente, che contiene proprio il numero 0x10000000 che però è memorizzato come byte3: 00 byte2: 00 byte1: 00 byte0: 10 Little Endian e Big Endian • Nell’esempio precedente avevamo: – indirizzo di base + offset ovvero: – 8($s2) = $s2 + 8 = 0x10000000 + 0x0008 = 0x10000000 + 0x00000008 = 0x10000008 ovvero (in formato Big Endian): $s2: 0x00 0x00 0x00 0x10 byte 3 byte 2 byte 1 byte 0 + 8: 0x08 0x00 0x00 0x00 byte 3 byte 2 byte 1 byte 0 0x08 0x00 0x00 0x10 byte 3 byte 2 byte 1 byte 0 = Spilling • In memoria si mettono le variabili meno usate • Ricorda: gli operandi aritmetici sono registri, non celle di memoria – tempo accesso ai registri e’ minore – 1 ciclo di clock: • lettura due registri, • esecuzione operazione • scrittura risultato * Organizzazione della memoria Global pointer ‐ offset a 16bit (4 cifre hex) ‐ permette di prelevare dati con un sola lw ‐ (0x10010020 = 0x8020($gp)) Static Data Dati statici Text Codice del programma (“text”) Esempio • Scrivere in assembly la seguente assegnazione – A[14] = b + A[6] con bÆ $s1, base(A) Æ $s0 lw $t0, 24($s0) add $t0, $s1, $t0 sw $t0, 56($s0) Vettori con indici variabili • Consideriamo $s3 $s1 a = b + A[i] • Informalmente: $s4 $s2 – Carica A[2] = lw $t0, 8($s3) – Carica A[i] = 4*$s4 + $s3 – = $s4+$s4+$s4+$s4+$s3 – b+A[i] = $s2+$s4+$s4+$s4+$s4+$s3 • Formalmente: – – – – – add $t1, $s4, $s4 add $t1, $t1, $t1 add $t1, $t1, $s3 lw $t0, 0($t1) add $s1, $s2, $t0 ricordate che per esprimere l’offset si hanno a disposizione solo 16 bit • Esercizio Scrivere in assembly la seguente istruzione: – A[4] = b + A[i] • Base A Æ $s1 • b Æ $s2 • i Æ $s3 • Scrivere in pseudo‐C il seguente codice Assembly: – – – – – – – add $t1, $s2, $s2 add $t1, $t1, $t1 add $t1, $t1, $s1 lw $t0, 0($t1) lw $t1, 16($s1) add $t1, $t1, $t0 sw $t1, 12($s1) Esercizio • Cominceremo la prossima lezione realizzando insieme (voi!) gli esercizi precedenti