Issuu on Google+

Esercitazione Il linguaggio assembler MIPS corso di

Didattica delle Applicazioni dell’Informatica modulo A Angelo Ciaramella angelo.ciaramella@uniparthenope.it


Sommario

• Riepilogo del set di istruzioni del MIPS Istruzioni matematiche Istruzioni di accesso alla memoria Istruzioni di salto branch e cicli Istruzioni per la chiamata a procedure e subroutine •Esempio • ordinamento di un vettore •Esercizi • Codifica nel linguaggio assembler MIPS di un programma scritto in C • Codifica nel linguaggio C di un programma in MIPS


Il linguaggio di progrmmazione  La notazione con cui è possibile descrivere gli algoritmi. Programma: è la rappresentazione di un algoritmo in un particolare linguaggio di programmazione. Ogni linguaggio di programmazione dispone di un insieme di “parole chiave” (keywords) Ogni linguaggio è caratterizzato da una sintassi e da una semantica


Il linguaggio di programmazione  Il linguaggio macchina

è direttamente eseguibile dall’elaboratore, senza nessuna traduzione. Il linguaggio assembler Le istruzioni corrispondono univocamente a quelle macchina, ma vengono espresse tramite nomi simbolici (parole chiave). Il programma prima di essere eseguito deve essere tradotto in linguaggio macchina (assemblatore). Vincolo: necessità di conoscere in dettaglio le caratteristiche della macchina (registri, dimensione dei dati, set di istruzioni) Anche semplici algoritmi implicano la specifica di molte istruzioni Il linguaggio ad alto livello. Sono i linguaggi di terza generazione. Le istruzioni esprimono una serie di azioni. Il programma prima di essere eseguito deve essere tradotto in linguaggio macchina (traduttore) Il programmatore può astrarre dai dettagli legati all’architettura ed esprimerei propri algoritmi in modo simbolico Sono indipendenti dalla macchina (astrazione)


Traduttore e assemblatore


Sviluppo di un programma  I traduttori sono programmi particolari che provvedono a convertire il codice di programmi scritti in un dato linguaggio di programmazione(sorgenti), nella corrispondente rappresentazione in linguaggio macchina (eseguibili) Compilatori Accettano in ingresso l’intero programma e producono in uscita la rappresentazione dell'intero programma in linguaggio macchina.

Interpreti Traducono ed eseguono direttamente ciascuna istruzione del programma sorgente, istruzione per istruzione.


Interpetri e compilatori  Compilatori Per ogni programma da tradurre, lo schema viene percorso una volta sola prima dell’esecuzione.

Interpreti Lo schema viene attraversato tante volte quante sono le istruzioni che compongono il programma; ad ogni attivazione dell'interprete su una particolare istruzione, segue l’esecuzione dell’istruzione stessa.

L’esecuzione di un programma compilato è più veloce dell'esecuzione di un programma interpretato


Architettura degli elaboratori • Dalla nascita dell’elaboratore a programma memorizzato, intorno al 1950, oggi poche sono state le innovazioni di rilievo nell’area dell’organizzazione e dell’architettura degli elaboratori. • L’architettura RISC (Reduced Instruction Set Computer) rappresenta un notevole passo in avanti rispetto alla tendenza storica dell’architettura per i processori. • Contrariamente esiste una architettura CISC (Complex Instruction Set Computer) che richiedono un insieme di istruzioni più ricchi con un gran numeri di istruzioni complesse.


Processore MIPS • Uno dei primi processori RISC a chip singolo comparso sul mercato fu sviluppato da MIPS Technology Inc. • Il sistema s’ispirava a un elaboratore sperimentale, anch’esso di nome MIPS sviluppato a Stanford • I modelli MIPS a 32 bit sono R2000 e R3000. Il modello MIPS R4000 è a 64 bit. • Le operazioni aritmetiche vengono effettuate tra registri e ci sono istruzioni dedicate per lo scambio di informazioni tra memoria e registri.


Introduzione • Il MIPS (Acronimo di Million Instruction Per Second, milioni di istruzioni per secondo) è un'unità di misura della potenza di un microprocessore. • Le istruzioni a cui si fa riferimento sono quelle assembly del processore in esame. • Tali istruzioni sono in genere molto semplici, ad esempio una singola somma o un singolo test per decidere se una condizione è vera o è falsa. • Un normale programma per computer è composto da migliaia o milioni di queste istruzioni, normalmente generate in modo automatico da un compilatore.


Istruzioni di trasferimento dati

• Gli operandi delle istruzioni aritmetiche devono provenire da un limitato numero di locazioni detti registri • La dimensione di un registro nella architettura MIPS è di 32 bit • Il MIPS ha 32 registri rappresentati nella notazione $0, $1, …, $31 • Le operazioni aritmetiche avvengono solo sui registri, quindi il processore MIPS deve possedere delle istruzioni di trasferimento dati fra la memoria e i registri


Allocazione dei registri Operandi del MIPS


Istruzioni aritmetiche Ogni istruzione aritmetica del MIPS deve avere esattamente tre variabili

Istruzioni aritmetiche

Esempio add a,b,c add a, a, d

# la somma di b e c è posta in a # la somma di b, c e d è posta in a


Istruzioni di trasferimento dati

• L’istruzione che trasferisce dalla memoria ai registri è chiamata load word (lw) formato: nome dell’operazione, registro da caricare, indirizzo di inizio della matrice e registro contenente l’indice dell’elemento della matrice da caricare nel registro specificato • L’istruzione che serve a trasferire un dato dai registri alla memoria è chiamata store (sw). formato: nome dell’operazione, registro da memorizzare, indirizzo di inizio della matrice e il nome del registro che contiene l’indice relativo all’elemento della matrice da memorizzare.


Istruzioni di trasferimento dati

Procedura in linguaggio C

Procedura swap in MIPS

swap(int v[ ], int k) { int temp; temp = v[k] v[k] = v[k+1]; v[k+1] = temp; }

lw $15, 0($2) lw $16, 4($2) sw $16, 0($2) sw $15, 4($2) jr $31


Istruzioni di scelta Il processore MIPS ha due istruzioni di tipo condizionale - beq register1, register2, L1 Questa istruzione dice di andare all’istruzione la cui etichetta è L1, se il valore di register1 è uguale a quello di register2 (branch equal) - bne register1, register2, L1 Questa istruzione dice di andare all’istruzione la cui etichetta è L1, se il valore di register1 è diverso da quello di register2 (branch not equal)


Istruzioni di scelta

Esempio di salto condizionato Codice C if (i == j) go to L1; f = g + h;

Codice MIPS Registri usati : $s0 ... $s4 = f ... j

L1: f = f - i;

beq $s3, $s4, L1 add $s0, $s1, $s2

#branch #skipped

L1: sub $s0, $s0, $s3 #always ex.


Istruzione if-then-else Costrutto if - then - else

Esempio Registri $s0, $s1, $s2, $s3, $s4 = f, g, h, i, j bne $s3, $s4, ELSE #branch add $s0, $s1, $s2 #skipped j EXIT ELSE: sub $s0, $s1, $s2 EXIT: ...


Ciclo sugli array Esempio di ciclo Loop: g = g + A [i]; i = i + j; if (i != h) goto Loop ....

Codice MIPS Registri usati : $s1, $s2, $s3, $s4 = g, h, i, j, array base = $s5 LOOP: add $t1, $s3, $s3 add $t1, $t1, $t1 add $t1, $t1, $s5 lw $t0, 0 ($t1) add $s1, $s1, $t0 add $s3, $s3, $s4 bne $s3, $s2, LOOP

#$t1 = 2 • i #$t1 = 4 • i #$t1 = adr. #load #g = g + A[i] #i = i + j


Istruzioni di salto incondizionato Istruzioni di salto incondizionato (jump) -j

address

- jr $s3

# address in reg. $3

Questa istruzione consente un salto incondizionato all’indirizzo specificato (j) o l’indirizzo centenuto nel registro specificato(jr)


Ciclo while Esempio di ciclo while while (save [i] == k) i = i + j; ....

Codice MIPS $s3, $s4, $s5 = i, j, k, array base = $s6 LOOP: add $t1, $s3, $s3 add $t1, $t1, $t1 add $t1, $t1, $s5 lw $t0, 0 ($t1) bne $t0, $s5, EXIT add $s3, $s3, $s4 j LOOP EXIT: ...

#$t1 = 2 • i #$t1 = 4 • i #$t1 = adr. #load #exit if <> #i = i + j


Istruzione SLT Istruzione imposta ad 1 se minore (set on - less than) Esempio - slt $8, $19,$20 Il registro $8 viene messo ad uno se il valore nel registro $19 è minore del registro $20

Esempio slt $1, $10, $11 bne $1, $0, LESS

#$1 = 1 if $10 < $11


Istruzione switch

Esempio di istruzione switch


Riepilogo delle istruzioni


Istruzioni con operandi immediati Istruzioni con operandi immediati - addi $29, $29, 4

# $29 = $29 + 4

lâ&#x20AC;&#x2DC;istruzione di somma ha una costante come operando - slti $8, $18, 10

$8 = 1 se $18 < 10

permette di fare un controllo immediato per lâ&#x20AC;&#x2122;istruzione di confronto di minoranza - lui $16, 61 permette di caricare in un registro i 16 bit piĂš significativi che corrispondono al numero decimale senza segno 61


Ciclo for Esempio di ciclo for in C for (i = 0; i< n ; i = i + 1 ) in C Codice MIPS Inizializzazione add $19, $0, $0 # i = 0 Istruzione di incremento addi $19, $19, 1 # i = i + 1 Ciclo for:

slt $8, $19, $5 beq $8, $0, exit

# il registro $8 = 0 se $19 ≥ $5 (i ≥n) #salta a exit se $19 ≥ $5 (i ≥n)

j for

#salta alla condizione del ciclo

….

exit: …


Procedure - La procedura è un metodo usato per strutturare i programmi in modo da essere più “leggibile” - Nel programma una volta eseguita una procedura si ritorna all’istruzione successiva alla sua chiamata - Il MIPS fornisce un’istruzione che forza il salto ad un indirizzo e simultaneamente salva quello dell’istruzione successiva nel registro $31 (indirizzo di ritorno) L’Istruzione salto con collegamento (jump and link, jal): - jal Indirizzo della procedura L’istruzione che effettua il rientro dalla chiamata a procedura: - jr $31

Le due istruzioni sono eseguite usando il Program Counter


Procedure

- Se una procedura a sua volta richiama unâ&#x20AC;&#x2122;altra procedura si deve salvare il vecchio indirizzo di ritorno $31 in una pila (stack) gestita con una politica di tipo LIFO - Sulla pila si possono fare le seguenti operazioni: Push inserire un elemento sulla pila Pop estrarre un elemento in cima alla pila


Esempio Procedura Swap in C swap(int v[ ], int k); { int temp; temp = v[k] v[k] = v[k+1]; v[k+1] = temp; }

La procedura swap scambia lâ&#x20AC;&#x2122;elemento k e lâ&#x20AC;&#x2122;elemento k+1 di un vettore v usando una variabile temporanea


Esempio (Swap in MIPS) Swap:

# Salvataggio registri utilizzati dalla procedura addi $29, $29, -12 #crea lo spazio sulla pila per tre registri sw $2, 0($29) #salva $2 sulla pila sw $15, 4($29) #salva $15 sulla pila sw $16, 8($29) #salva $16 sulla pila # Corpo della procedura muli $2, $5, 4 #registro $2 = k * 4 add $2, $4, $2 #registro $2 = v + (k*4) lw $15, 0($2) # il registro $2 contiene lâ&#x20AC;&#x2122;indirizzo di v[k] lw $16, 4($2) # $15 = v[k] e $16 = v[k+1] sw $16, 0($2) #v[k] = registro $16 sw $15, 4($2) #v[k+1] = registro $15 (temp) # Rispristino dei registri lw $2, 0($29) #rispristina $2 dalla pila lw $15, 4($29) #rispristina $15 dalla pila lw $16, 8($29) #rispristina $16 dalla pila addi $29,$29, 12 # ripristina il puntatore alla pila # Ritorno alla procedura chiamante jr $31


Esempio (Sort) La procedura ordina un vettore di 10000 interi. La procedura richiama la procedura Swap vista in precedenza Codice C Int v[10000]; Int i,j; sort (int v[ ], int n ) { for (i=0;i<n;i=i+1) { for(j=i-1; j>=0 && v[j]> v[j+1]; j=j-1) { swap(v,j) } } }


Esempio (Sort in MIPS) - I due parametri della procedura sort (v ed n) sono rispettivamente nei registri $4 e $5, mentre $19 e $17 sono destinati a i e j Procedura in MIPS Sort: # Salvataggio dei registri usati successivamente da swap addi $29, $29, -36 #riserva spazio sulla pila per 9 registri sw $15, 0($29) #salva $15 sulla pila sw $16, 4($29) #salva $16 sulla pila sw $17, 8($29) #salva $17 sulla pila sw $18, 12($29) #salva $18 sulla pila sw $19, 16($29) #salva $19 sulla pila sw $20, 20($29) #salva $20 sulla pila sw $24, 24($29) #salva $24 sulla pila sw $28, 28($29) #salva $28 sulla pila sw $31, 32($29) #salva $31 sulla pila


Esempio (Sort in MIPS) # Corpo della procedura # I maggiori problemi restano nel passaggio dei parametri alla procedura (v ed n in # $4 e $5). Una soluzione è quella di copiare i parametri per la procedura sort # per renderli disponibili alla procedura swap # Spostamento parametri move $18, $4 move $20, $5 # Ciclo più esterno add $19, $0, $0 for1tst: slt $8, $19, $20 beq $8, $0, exit1

#copia parametro $4 in $18 #copia parametro $5 in $20

#i=0 # registro $8 = 0 se $19 ≥ $20 (i ≥n) # salta ad exit1 se $19 ≥ $20 (i ≥n)


Esempio (Sort in MIPS) # Ciclo più interno addi $17, $19, -1 #j = i -1 for2tst: slti $8, $17, 0 # registro $8 = 1 se $17 < 0 (j<0) bne $8, $0, exit2 # salta ad exit2 se $17 < 0 (j<0) muli add lw lw slt beq

$15, $17, 4 $16, $4, $15 $24, 0($16) $25, 4($16) $8, $25, $24 $8, $0, exit2

#registro $15 = j*4 # registro $16 = v + (j*4) # registro $24 = v[j] # registro $25 = v[j+1] # registro $8 = 0 if $25 ≥ $24 # salta ad exit2 se $25 ≥ $24

# Passaggio parametri e chiamata move $4, $18 move $5, $17 jal swap

#il primo parametro di swap è v # il secondo parametro di swap è j


Esempio (Sort in MIPS) # Ciclo pi첫 interno addi $17, $17, -1 j for2tst

#j = j -1 #salta alla condizione del ciclo pi첫 interno

# Ciclo pi첫 esterno exit2: addi $19, $19, 1 j for1tst

#i = i + 1 #salta alla condizione di ciclo pi첫 esterno

# Rispristino dei registri exit1: lw $15, 0($29) lw $16, 4($29) lw $17, 8($29) lw $18, 12($29) lw $19, 16($29) lw $20, 20($29) lw $24, 24($29) lw $28, 28($29) lw $31, 32($29) addi $29,$29,36

#ripristina $15 dalla pila #rispristina $16 dalla pila #rispristina $17 dalla pila #rispristina $18 dalla pila #rispristina $19 dalla pila #rispristina $20 dalla pila #ripristina $24 dalla pila #ripristina $28 dalla pila #rispristina $31 dalla pila #ripristina il puntatore alla pila

# Ritorna alla chiamata della procedura jr $31


Allocazione dei registri GNU MIPS C register allocation -$zero 0 constant 0 -$at 1 assembler -$v0 ... $v1 2-3 result value registers -$a0 ... $a3 4-7 arguments -$t0 ... $t7 8-15 temporary variables -$s0 ... $s7 16-23 saved -$t8 ... $t9 24-25 temporary variables -$k0 ... K1 26-27 operating system -$gp 28 global pointer -$sp 29 stack pointer -$fp 30 frame pointer -$ra 31 return address


Esercizio Tradurre nel linguaggio macchina MIPS la procedura sum_min (e la procedura chiamata calc_min) che effettua la somma tutti i valori del vettore v e sottrae alla somma il minimo Procedura sum_min Procedura calc_min int v[100]; int calc_min(int v [ ], int n) int n; { n = 100; int k; int sum_min(int v[ ], int n) { min = v[0]; for (k = 1; k<n; k = k + 1) int minimo, j, sum; { sum = 0; if v[k] < min for (j = 0; j < n; j = j + 1) min = v[k]; { sum = sum + v[j]; } } return min minimo = calc_min(v,n); } operazione = sum â&#x20AC;&#x201C; minimo; return operazione }


Esercizio (soluzione) Registri usati da sum_min:

Registri usati da calc_min:

$a0 - vettore v $a1 - parametro n $v0 - registro per la variabile di return $t0 - indice j $t1 - variabile sum $t2 - variabile minimo $s0 - registro per copiare $a0 $s1 - registro per copiare $a1 $t3-$t7 - registri per variabili temporanee $t8-$t9 - registri per variabili temporanee (load -store)

$a0 - vettore v $a1 - parametro n $v1 - registro per la variabile di return $t0 - indice k $t8 - variabile min $t3-$t7,$t9 - registri per variabili temporanee (load -store)

Ă&#x2C6; permesso lâ&#x20AC;&#x2122;uso di: move Esempio: move $4, $20 # copia nel registro $4 il contenuto del registro $20


Esercizio (soluzione di sum_min) Salvataggio registri

sum_min: addi $sp, $sp, -36 sw $s0, 0($sp) sw $s1, 4($sp) sw $t0, 8($sp) sw $t1, 12($sp) sw $t3, 16($sp) sw $t4, 20($sp) sw $t5, 24($sp) sw $t8, 28($sp) sw $ra, 32($sp)

Corpo della procedura

move $s0, $a0 move $s1, $a1 add $t1, $0, $0 add $t0, $0, $0

# copia di $a0 in $s0 # copia di $a1 in $a1 # inizializzazione di sum (sum = 0) # inizializzazione di j (j = 0)


Esercizio (soluzione di sum_min) Ciclo for For: slt beq muli add lw add addi j

$t3, $t0, $s1 $t3, $0, EXIT $t4, $t0, 4 $t5, $s0, $t4 $t8, 0($t5) $t1, $t1, $t8 $t0, $t0, 1 For

# controllo (j < n) # aggiornamento indice del ciclo ($t4 = j*4) # $t5 = v + j*4 # $t8 = v[j] # sum = sum + v[j] #j=j+1 # salto alla label For

Opzione EXIT EXIT: move $a0,$s0 move $a1, $s1 jal calc_min add $v0, $t1, $v1

# copia dei registri usati in calc_min # chiamata alla funzione calc_min # calcolo di sum - minimo


Esercizio (soluzione di sum_min) Ripristino registri lw $s0, 0($sp) lw $s1, 4($sp) lw $t0, 8($sp) lw $t1, 12($sp) lw $t3, 16($sp) lw $t4, 20($sp) lw $t5, 24($sp) lw $t8, 28($sp) lw $ra, 32($sp) addi $sp, $sp, 36 jr $ra

# ritorno alla procedura chiamante


Esercizio (soluzione di calc_min) Salvataggio registri

calc_min: addi $sp, $sp, -28 sw $t0, 0($sp) sw $t1, 4($sp) sw $t2, 8($sp) sw $t3, 12($sp) sw $t4, 16($sp) sw $t8, 20($sp) sw $t9, 24($sp) sw $ra, 28($sp)

Corpo della procedura lw

$t8, 0($a0)

addi $t0, $t0, 1

# min = v[0] #k=1


Esercizio (soluzione di calc_min) For: slt $t1, $t0, $a1 beq $t1, $0, EXIT muli $t2, $t0, 4 add $t3, $a0, $t2 lw $t9, 0($t3) slt $t4, $t9, $t8 beq $t4, $0, L1 move $t8, $t9 L1 : addi $t0, $t0, 1 j For

EXIT: move $v1, $t8

# k< n

# aggiornamento indice k # caricamento di v[k] # v[k] < min


Esercizio (soluzione di calc_min) Ripristino registri lw $t0, 0($sp) lw $t1, 4($sp) lw $t2, 8($sp) lw $t3, 12($sp) lw $t4, 16($sp) lw $t8, 20($sp) lw $t9, 24($sp) lw $ra, 28($sp) addi $sp, $sp, 28

jr $ra

# ritorno alla procedura chiamante


Esercizio (potenza di un numero) Programma in C per il calcolo della potenza di un numero int power (int base, int n) { int i, p; i = 0; p = 1; while (i < n) { i = i + 1; p = p * base; } }


Esercizio (soluzione) sub $sp, $sp, 12 sw $s0, 0($sp) sw $t1, 4($sp) sw $t0, 8($sp) add $t0, $0, $0 addi $s0,$0, 1

Salvataggio registri Assumiamo $a0 = base; $a1 = n; $t0 = i ; $t1 = flag; $s0 = p Corpo del programma

LOOP: slt beq addi mul j

$t1, $t0, $a1 $t1, $0, EXIT $t0, $t0, 1 $s0, $s0, $a0 LOOP

# i>=n esco dal ciclo # i=i+1; # p=p*base;

EXIT: add $v0, $s0, $0 lw $s0, 0($sp) lw $t1, 4($sp) lw $t0, 8($sp) add $sp, $sp, 12 jr, $ra

# p nel registro di ritorno Ripristino registri


MIPS