Index
Registri
Cosa sono?
Sono celle di memoria che contengono dei valori che verranno assegnati nel file di lavoro
Registri principali
Quali sono?
$zero
registro che contiene la costante 0
- Tutti i registri vengono inizializzati con lo stesso valore
$v0
e$a0
usati per le syscalls- Da
$t0
a$t9
sono registri temporanei$s0
e$s7
registri temporaneicoproc1
ecoproc0
registri che contengono double e float
Sintassi per creare un programma in Assembly
.globl main
- All’inzio del programma si deve scrivere
Global main
- Può essere accessibile a tutti i file
.data
- In questa sezione si elencano tutte le variabili che utilizzeremo nel
.text
.text
- Vengono scritti tutti i comportamenti delle variabili (quello che devono svolgere)
Ex.
.globl main
.data
numero: .word 1 //rappresentato in 32 bit
.text
main:
- la variabile numero non si trova in nessun registro
Caricare le variabili nei registri (lw)
- Serve per caricare la variabile all’interno di un registro
.globl main
.data
numero: .word 1 //rappresentato in 32 bit
.text
main:
lw $t0, numero
Spostare il valore in un altro registro (move)
- Possiamo spostare il valore in altri registri
.globl main
.data
numero: .word 1 //rappresentato in 32 bit
.text
main:
lw $t0, numero
move $t1, $t0 //il valore di $t0 deve essere spostato nel resitro $t1
Warning
Con
move
non sto spostando il valore, il registro$t0
non si svuota ma sto copiando e incollando il valore nel registro$t1
Somma tra interi (add e addi)
Add
add $t2, $t0, $zero //posso scrivere anche $0
- Il primo registro
$t2
è il registro di destinazione $t0
e$zero
sono gli addendi
Addi
- “add con i”
- La i sta per “immediato”
addi $t3, $t0, 0
- In
$t3
carico la somma tra$t0
e 0 addi
si usa quando si ha come terzo operando un numero
Sottrazione tra interi (sub e subi)
Sub
sub $t2, $t0, $zero
$t2
è il registro di destinazione- Esegue la somma tra
$t0
e$zero
Subi
subi $t3, $t0, 5
$t2
è il registro di destinazione- Esegue la somma tra
$t0
e 5 - Viene usato quando il terzo operando quando è un intero
Ex.
- Differenza tra due registri
.globl main
.data
numero0: .word 10
numero1: .word 5
.text
main:
lw $t0, numero0
lw $t1, numero1
sub $t2, $t0, $t1
- Esegue la differenza tra
$t0
e$t1
Sottrazione senza caricare un .data (li)
.globl main
.data
numero0: .word 10
.text
main:
lw $t0, numero0
li $t1, 5
sub $t2, $t0, $t1
- Carico nel registro
$t1
un qualcosa di immediato
Syscall
Cosa sono?
Sono tutte quelle chiamate al sistema che vengono scritte per stampare una variabile, chiedere un valore e chiudere un programma
Stampare una variabile
li $v0, 1 //ho intenzione di stampare un numero
move $a0, $t2 //il contenuto di $t2 va spostato in $a0
syscall
- Se vogliamo stampare un numero di deve passare al registro
$v0
il valore 1 $a0
è il registro che contiene il valore da stampare- In questo caso il comando
syscall
equivale a direprint()
Chiudere un programma (li $v0, 10)
li $v0, 10 //ho intenzione di terminare l'esecuzione del programma
syscall //chiude il programma
- Per chiudere il programma bisogna caricare il registro
$v0
il valore 10 - In questo caso il comando
syscall
chiude il programma
Warning
Bisogna sempre ricordarsi che di chiudere un programma
Operazioni con le stringhe
.globl main
.data
stringa: .asciiz "ciao"
.text
main:
la $t0 stringa
li $v0, 4
move $a0, $t0
syscall
li $v0, 10
syscall
.asciiz
serve per definire la stringa- Per stampare una stringa si deve caricare nel registro
$v0
il valore 4
Cosa cambia tra load word e load address?
lw
carica 1 parola (32 bit)la
carica l’indirizzo della variabile
Stampare un character
- Il valore viene rappresentato in 8 bit
.globl main
.data
char: .byte 'v'
.text
main:
la $t0, char // carico in $t0 il char
li $v0, 4 //voglio stampare il char
move $a0, char //sposto il char nel registro $a0
syscall //eseguo
//modo alternativo
li $v0, 4
la $a0, char
syscall
li $v0, 10
syscall
Perché c'è
load address
invece dimove
?
- Se si vuole usare il move bisogna prima caricare il carattere in un registro
- Con
load address
ho caricato direttamente in$a0
il valore char
- Questa operazione è più efficiente poiché la macchina dovrà fare un’operazione in meno
- Il programma stampa due v attaccate
- Se avessi voluto inserire uno spazio tra le due v dovrei scrivere:
.globl main
.data
char: .byte 'v'
spazio: .asciiz "¥n"
.text
main:
la $t0, char // carico in $t0 il char
la $t1, spazio //caricp lo spazio in $t1
li $v0, 4
move $a0, spazio
syscall
li $v0, 4 //voglio stampare il char
move $a0, char //sposto il char nel registro $a0
syscall //eseguo
li $v0, 4
la $a0, char
syscall
li $v0, 10
syscall
Stampare un float
.globl main
.data
PI: .float 3.14
.text
main:
li $v0, 2
lwc1 $f12, PI //carico PI in $f12
syscall
li $v0, 10
syscall
- Per stampare un float si deve caricare nel registro
$v0
il valore 2 $f12
svolge lo stesso ruolo di$a0
- La differenza è che in
$a0
viene inserito tutto ciò che non è float o double
- La differenza è che in
lwc
sta per load word coproc
Operazioni con i double
.globl main
.data
n: .double 3.1
m: .double 2.12
.text
main:
ldc1 $f0, n
ldc1 $f2, m
li $v0,3
add.d $f12, $f2, $f0 //svolgo la somma tra $f2 e $f0 e poi sposto il risultato el registro $f12
li $v0, 10
syscall
ldc
è solo per i doublem
lo carico nel registro$f2
poiché i double utilizzano 64 bit- Per stampare un double si deve caricare nel registro
$v0
il valore 3 - Nel
add.d
, il .d specifica che è un double
Comandi mult
e mflo
Mul
e mult
.globl main
.data
uno: .word 10
due: .word 5
.text
main:
lw $t0, uno
lw $t1, due
mul $t2, $t0, $t1 // fa il prodotto tra $t0 e $t1 e lo carica nel registro $t2
//metodo alternativo con mult
mult $t0, $1 //esegue il prodotto e lo carica in $lo
mflo $t2 //"sposta" il prodotto da $lo a $t2
li $v0, 10
syscall
Differenza tra
mul
emult
mul
prende tre registri ($t2
,$t0
,$t1
)mult
moltiplicazione tra due registri
- il risultato viene caricato nel registro
$lo
- per spostare il valore in un altro registro uso
mflo
(move from lo)
Divisioni
Div
e divu
.globl main
.data
Uno: .word 10
Due: .word 2
.text
main:
lw $t0, Uno
lw $t1, Due
div $t2, $t0, $t1 //div esegue la divisione tra $t0 e $t1
li $v0, 1
move $a0, $t2
syscall
//metodo alternativo con divu
divu $t0, $t1
mflo $t2
li $v0, 10
syscall
Cosa succede se la divisione con il resto?
La parte intera viene caricata nel registro
$lo
e il resto viene caricato nel registro$hi
- Per spostare il resto in un registro si deve fare
divu $t0, $t1
mflo $t2
mfhi $t3 //sposta il resto nel registro $t3
Funzioni
.globl main
.data
.text
main: //dichiarazione funzione main
li $t0, 1
li $t1, 2
li $t2, 3
li $t3, 6
Operazioni: //dichiarazione funzione Operazione
mul $s0, $t0, $t1 // moltiplica 1*2
div $s1, $t3, $t2 // divide 6/3
add $a2, $s0, $s1 // addiziona riga 12 + riga 14
StampaEtermina: // dichiarazione funzione StampaEtermina
li $v0, 1
move $a0, $s1
sys call
li $v0, 1
move $a0, $s2
syscall
li $v0, 10
syscall
Sto dividendo il programma in più parti
Jump
Salto incondizionato che “salta” da una funzione all’altra
.globl main
.data
.text
main: //dichiarazione funzione main
li $t0, 1
li $t1, 2
li $t2, 3
li $t3, 6
j stampaEtermina
Operazioni: //dichiarazione funzione Operazione
mul $s0, $t0, $t1 // moltiplica 1*2
div $s1, $t3, $t2 // divide 6/3
add $a2, $s0, $s1 // addiziona riga 12 + riga 14
stampaEtermina: // dichiarazione funzione StampaEtermina
li $v0, 1
move $a0, $s1
sys call
li $v0, 1
move $a0, $s2
syscall
li $v0, 10
syscall
Info
- La funzione a
j stampaEtermina
salta e va alla funzionestampaEtermina
- La funzione a
j Operazioni
salta e va alla funzioneOperazione
- Il programma:
- Carica nei registri i valori dichiarati
- Va a
stampaEtermina
Scorrimento vettore word
.global main
.data
vettore: .word 1,2,3,4,5,6,7,8,9,10 //10 elementi: 10 word
N: .word 10 // len del vettore
capo: .asciiz "\n"
.text
main:
li $t0, 0 //carico in $t0 il valore 0
lw $t1, N // carico in $t1 la wword N
la $t4, capo //carico in $t1 lo \n
while: //funzione while
bge $t0, $t1, end //quando l'indice è uguale o maggiore alla len del vettore il programma jumpa alla funzione end
sll $t3, $t0, 2 //shifta di 2 moltiplicando $t0*2
lw $t3 vettore ($t3) //carico il vettore[indice]
li $v0, 1
move $a0, $t3
syscall
addi $t0, $t0, 1 //indice++
j while //salto al loop
end:
li $v0, 0
syscall
Info
- Il comando
bge
(branch if greater or equal then) è una condizione per il while
- Significa che il loop terminerà solo quando t1 (esempio in python
while i <= N
)
Warning
- Quando faccio
lw $t3 vettore[indice]
non basta per incrementare l’indice- Devo incrementarlo con il comando
addi
Scorrimento vettore con puntatore
.global main
.data
vettore: .word 1,2,3,4,5,6,7,8,9,10
N: .word 10
capo: .asciiz "\n"
.text
main:
la $t0, vettore //carico l'indirizzo del vettore
lw $t1, N //carico la len del vettore
sll $t1, $t1, 2 //faccio lo shift logico della len = 10*4 (offset)
add $t1, $t1, $t0 //addizioniamo l'offset + indirizzo vettore
la $t4, capo
loop:
bge $t0, $t1, fine //confronto l'indirzzo del vettore e la len
lw $t3, ($t0) //nel registro $t3 carico vettore[indice]
li $v0, 4
move $a0, $t4
syscall
addi $t0, $t0, 4 //incremento l'indice
j loop
fine:
li $v0, 10
syscall
Jump and Link
.global main
.data
vettore: .word 1,2,3,4,5,6,7,8,9,10
N: .word 10
capo: .asciiz "\n"
.text
main:
la $t0, vettore
li $t1, 0
lw $t2, N
la $t3, capo
jal Funzione
li $v0, 10
syscall
Funzione:
while:
bge $t1, $t2, fine //condizione while
sll $t4, $t1, 2 //shift del registro per andare all'indice successivo
add $t4, $t0, $t4 //indirizzo vettore + offeset
lw $t4, ($t4) //lettura del vettore[indice]
li $v0, 1
move $a0, $t3
syscall
li $v0, 4 //creo spazio per avere una colonna di valori
move $a0, $t3
syscall
addi $t1, $t1, 1 //incremento dell'indice
j while
fine:
jr $ra
Funzione
jal
- Oltre al jump c’è un collegamento
- Memorizza il valore del program counter (indirizzo dell’istruzione successiva PC+4) nel registro
$ra
Jump register
- Quando finisce l’iterazione non c’è più la semplice
syscall
, ma c’èjr $ra
- Devo saltare alla funzione che ho chiamato (vado alla riga dopo il
jal Funzione
)
Info
E’ buona norma utilizzare il Jump and Link per rendere il programma ben strutturato
Esercizio somma elementi di un vettore
.globl main
.data
vettore: .word 1,2,3,4,5,6,7,8,9,10 //vettore
N: .word 10 //len del vettore
capo: .asciiz "\n"
.text
main: //funzione principale
la $t0, vettore //indirizzo del vettore in $t0
li $t1, 0 //indice
lw $t2, N //carico la len del vettore
la $t3, capo //carico lo \n
jal Funzione
li $v0, 1
move $a0, $t5
syscall
li $v0, 10
syscall
Funzione:
while: bge $t1, $t2, fine
sll $t4, $t1, 2 //offset
add $t4, $t4, $t0 //offset + indirizzo del vettore
lw $t4, ($t4) //vettore[indice]
add $t5, $t5, $t4 //sommo gli elementi del vettore e li inserisco in $t5
addi $t1, $t1, 1 //incremento il contatore
j while
fine: jr $ra
Esercizio somma elementi pari di un vettore
.globl main
.data
vettore:.word 1,2,3,4,5,6,7,8,9,10 //vettore
N:.word 10
capo:.asciiz "-"
.text
main:
la $t0, vettore //carico il vettore in $t0
li $t1, 0
lw $t2, N
li $t4, 2 //divisore
jal Funzione
li $v0, 10 //chiude il programma
syscall
Funzione:
while:
bge $t1, $t2, fine
sll $t3, $t1, 2 //shift logico dell'indice per 4, offset
add $t3, $t3, $t0 //somma tra vettore e offset
lw $t3, ($t3) //vettore[indice]
divu $t3, $t4 //divido il numero per 2 per vedere se è pari
mfhi $t5 //carico il resto della divisione in $t5
beq $t5,0, pari //condizione
//se falso
j incremento
//se vero
pari:
li $v0, 1
move $a0, $t3 //stampo il valore
syscall
j incremento
incremento:
addi $t1, $t1, 1
j while
fine:
jr $ra
Loop e salti condizionati
Condizioni
beq
(branch if equal)
beq $t0, $t1, fine
Info
Salta alla funzione
fine
se$t0 == $t1
bge
(branch on greater or equal)
bge $t0, $t1, fine
Info
Salta alla funzione
fine
quando$t0 >= $t1
.eqv
Info
Serve per rinominare i registri
.eqv indice $t0 //rinomino $t0 con il nome "indice"
- Quando definisco le operazioni non scriverò
$t0
ma scriverò direttamenteindice
addi indice, indice, 1
- Si possono anche rinominare le funzioni
.data
.eqv indice $t0
.eqv numero $t1
.eqv incremento addi indice, indice 1
.text
while: beq, indice, numero fine
incremento
j while
Esercizio somma elementi indici pari e indici dispari
.globl main
.data
vettore: .word 1,3,1,3,1,3,1,3,1,3 #vettore
N: .word 10 #len vettore
spazio: .asciiz "\n"
.text
main:
la $t0, vettore
li $t1, 0 #indice vettore
lw $t2, N
li $t3, 2
la $t9, spazio
jal Funzione
li $v0, 1
move $a0, $t6
syscall
li $v0, 4
move $a0, $t9
syscall
li $v0, 1
move $a0, $t7
syscall
li $v0, 10
syscall
Funzione:
while:
bge $t1, $t2, fine
sll $t4, $t1, 2 #shift logico
add $t4, $t4, $t0 #somma tra vettore e offset
lw $t4, ($t4) #vettore[indice]
divu $t1, $t3 #divido l'indice per 2
mfhi $t5 #carico il resto in $t5
bne $t5, $zero, dispari
add $t6, $t6, $t4
j incremento
dispari:
add $t7, $t7, $t4
incremento:
addi $t1, $t1, 1
j while
fine:
jr $ra
Matrici
Definizione di una matrice
matrice: .word 0:400
dim: .word 20 //lato della matrice
Info
0
significa che è inizializzata a 0400
significa che è una matrice quadrata 20x20
Ex. somma diagonali di una matrice
.globl main
.data
matrice: .word 0:400 //matrice 20x20
dim: .word 20 //lato della matrice
.text
main:
move $t0, $0 //inizializzo coordinata x
move $t1, $0 //inizializzo coordinata y
move $t2, $0 //inizializzo somma iniziale
lw $t3, dim //carico il lato della matrice
cicloRighe: //scorre le righe
bge $t1, $t3, fine
ciclo colonne:
bge $t0, $t3, nextRiga
beq $t0, $t1, sommaDiagonali
addi $t0, $t0, 1
j ciclo colonne
sommaDiagonali:
add $t2, $t1, $t0
sll $t0, $t0, 2 //PC + 4
lw $t0, matrice($t0)
nextRiga:
li $t0, 0 //azzera il contatore della coordinata x
addi $t1, $t1, 1 //aggiorna il contatore delle righe
j cicloRighe
fine:
li $v0, 1
move $a0, $t2
syscall
li $v0, 10 //chiude il programma
syscall
Scorrere un vettore al contrario (in range (len(vettore), 0)
)
.globl main
.data
vettore: .word 1,2,3,4,5,6,7,8,9,10 //vettore
N: .word 0 //dimensione vettore
capo: .asciiz "\n"
.text
main:
la $t0, vettore
li $t1, 9 //indice vettore
lw $t2, N
la $t3, capo
while:
blt $t1, $t2, fine //controlla se $t1 < $t2
sll $t4, $t1, 2
add $t4, $t4, $t0
lw $t4, ($t4)
stampa:
subi $t1, $t1, 1
li $v0, 1
move $a0, $t4
syscall
li $v0, 4
move $a0, $t3
syscall
j while
fine:
li $v0, 10
syscall
Doppio scorrimento di un vettore
.globl main
.data
vettore: .word 1,2,3,4,5,6,7,8,9,10 //vettore
N: .word 5 //stop while 1
M: .word 4 //stop while 2
capo: .asciiz "\n"
.text
main:
la $t0, vettore
li $t1, 0 //indice vettore che parte dall'inizio
lw $t2, N
la $t3, capo
lw $t5, M
li $t6, 9 //indice del vettore che parte dalla fine
move $s0, $0 //somma
while1:
bge $t1, $t2, fine
while2:
ble $t6, $t5, fine
sll $t4, $t1, 2
sll $t7, $t6, 2
add $t4, $t4, $t0
add $t7, $t7, $t0
lw $t4, ($t4)
lw $t7, ($t7)
addizione:
add $s0, $t4, $t7
li $v0, 1
move $a0, $s0
syscall
li $v0, 4
move $a0, $t3
syscall
addi $t1, $t1, 1
subi $t6, $t6, 1
j while1
fine:
//bge $t5, $t6, while2 (?)
li $v0, 10 //chiude il programma
syscall