TD Architecture des ordinateurs

publicité
ARCHITECTURE DES ORDINATEURS
IG3 2012-2013
TD 4 : Introduction au langage MIPS
Clément Jonquet
{[email protected]}
Environnement de travail
Nous allons utiliser un simulateur pour le langage MIPS. Étant donné la grande utilisation
de MIPS, plusieurs simulateurs sont disponibles (e.g., SPIM, MARS, MIPSter, etc.). Si vous
êtes sur votre machine personnelle vous pouvez utiliser SPIM ou MARS ; si vous êtes sur une
machine Polytech, il vous faut utiliser MARS, qui est une application Java et qui ne nécessite
pas d'installation.
SPIM (http://pages.cs.wisc.edu/~larus/spim.html) de James R. Larus (Microsoft,
Univ. of Wisconsin) ;
MARS (http://courses.missouristate.edu/KenVollmar/MARS/index.htm) de Ken Vollmar (Missouri State Univ.).
Les 2 environnements de programmation proposent un mode "step-by-step" qui permet d'exécuter les instructions les unes après les autres. Ce mode va nous intéresser pour comprendre les
mécanismes de la programmation assembleur. Quel que soit l'environnement choisi, les généralités de MIPS nécessaires au TD sont rappelés ci-après.
Généralités MIPS
Syntaxe
Les commentaires commencent par le symbole # et se terminent à la n de la ligne.
Un identicateur est une séquence de caractères alphanumériques, de soulignés (_) et de
points (.), qui ne commence pas par un chire.
Les codes opération d'instruction sont des mots réservés qui ne peuvent pas être utilisés
comme identicateurs.
Les étiquettes sont déclarées en les plaçant au début d'une ligne et en les faisant suivre du
symbole :.
Les nombres sont en base 10 par défaut. S'ils sont précédés de 0x ils sont interprétés comme
hexadécimaux.
Les chaînes de caractères sont encadrées par des doubles apostrophes ".
Certains caractères spéciaux dans les chaînes de caractères suivent la convention C :
retour-chariot : \n
tabulation : \t
guillemet : \"
Directives
.ascii str Enregistre en mémoire la chaîne de caractères str, mais ne la termine pas par un
caractère nul.
.asciiz str Enregistre en mémoire la chaîne de caractères str et la termine par un caractère
nul.
.data<@> Les éléments qui suivent sont enregistrés dans le segment de données. Si l'argument
optionnel @ est présent, les éléments qui suivent sont enregistrés à partir de l'adresse @.
.byte b1 , . . . ,bn Enregistre les n valeurs dans des octets consécutifs en mémoire.
.word w1 , . . . ,wn Enregistre les n quantités 32 bits dans des mots consécutifs en mémoire.
.float f1 , . . . ,fn Enregistre les n nombres ottants simples précision dans des emplacements
mémoire consécutifs.
.text <@> Les éléments qui suivent sont placés dans le segment de texte de l'utilisateur. Dans
SPIM, ces éléments ne peuvent être que des instructions ou des mots. Si l'argument optionnel @ est présent, les éléments qui suivent sont enregistrés à partir de l'adresse @.
.globl sym Déclare que le symbole sym est global et que l'on peut y faire référence à partir
d'autres chiers.
Les registres
Il existe 32 registres de 32 bits numérotés $0, . . . , $31 ; les registres peuvent être accédé soit
par leur numéro soit par leur nom.
Nom
$zero
$at
$v0,$v1
Numéro
0
1
2-3
$a0,. . .,$a3
$t0,. . .,$t7
$s0,. . .,$s7
$t8,$t9
$k0,$k1
4-7
8-15
16-23
24-25
26-27
$gp
$sp
$fp
$ra
28
29
30
31
Description
Constante 0
Réservé à l'assembleur
Évaluation d'une expression et résultats
d'une fonction
Arguments de sous-programmes
Valeurs temporaires (non préservées)
Valeurs temporaires (préservées)
Valeurs temporaires (non préservées)
Réservé pour les interruptions (i.e., système
d'exploitation)
Pointeur global
Pointeur de pile
Pointeur de bloc
Adresse de retour
Appel de procédure - conventions
Par convention, lors de l'appel de procédure, les registres $t0,. . .,$t9 sont sauvegardés par
l'appelant et peuvent donc être utilisés sans problème par l'appelé. Les registres $s0,. . .,$s7
doivent quand à eux être sauvegardés et restitués exact par l'appelé.
La pile croit des adresses hautes vers les adresses basses : on soustrait à $sp pour allouer
de l'espace dans la pile, on ajoute à $sp pour rendre de l'espace dans la pile.
Les déplacements dans la pile se font sur des mots mémoire entiers (multiples de quatre
octets).
Lors du passage de passage de paramètres : tout paramètre plus petit que 32 bits est
automatiquement promu sur 32 bits.
Les quatre premiers paramètres sont passés par les registres $a0,. . .,$a3. Les paramètres
supplémentaires sont passés dans la pile.
Toute valeur de format inférieur ou égal à 32 bits est retournée par le registre $v0 (sur 64
bits $v1 est utilisé avec $v0).
2
Gestion de la mémoire
Les appels système
Les simulateurs fournissent un ensemble de services par l'intermédiaire de l'instruction d'appel syscall. Pour demander un service on charge le code du service (voir tableau ci-dessous)
dans le registre $v0 et ses arguments dans les registres $a0,...,$a3 (ou $f12 pour les valeurs
ottantes). Les appels système qui retournent des valeurs placent leurs résultats dans le registre
$v0 (ou $f0 pour les résultats ottants).
service
print_int
print_oat
print_double
print_string
read_int
read_oat
read_double
read_string
sbrk
exit
code
1
2
3
4
5
6
7
8
9
10
arguments
$a0 = entier
$f12 = ottant simple précision
$f12 = ottant double précision
$a0 = chaîne de caractères
$a0 = tampon, $a1 = longueur
$a0 = quantité
résultat
un entier dans $v0
un ottant simple dans $v0
un ottant double dans $v0
une adresse dans $v0
Par exemple, le code suivant imprime la réponse = 5 .
str:
main:
.data
.asciiz
.text
li
la
syscall
li
li
syscall
"la réponse = "
$v0,4
$a0,str
#code appel système print_str
#adresse chaîne à imprimer
#on imprime la chaîne
#code appel système print_int
#entier à imprimer
#on l'imprime
$v0,1
$a0,5
3
Questions
Question 1
Enregistrer dans un chier et exécuter le code ci-dessus.
(a) A quelle adresse est chargée le début de la chaîne de caractère str ?
0x10010000
(b) Quelle est la signication des instructions lui $1,4097 et ori $4,$1, 0, rajoutées par l'assembleur ?
Le chargement d'une adresse 32 bits n'existe pas en MIPS (rappelez vous que les adresses
sont sur 16 bits dans les instructions de type I). Il faut donc traduire la pseudo instruction
la $a0,str en instructions MIPS. Ceci est réalisé en plaçant dans les bits de poids fort d'un
registre (ici $1 = $at) réservé à l'assembleur l'adresse du début du segment de donnée (lui
$1,4097) et dans les bits de poids faible, l'adresse relative dans le segment de donnée (ori
$4,$1, 0).
(c) Rajouter une autre chaîne de caractère avant str dans le code. Que devient l'instruction ori ?
Elle change l'immédiat pour s'adapter à la nouvelle position de la chaîne de caractères dans
le segment de données.
Question 2
Traduire en MIPS les aectations suivantes en continuant le programme ci-dessous :
.data
.asciiz ", "
.text
li
$t1, 10
li
$t2, 50
li
$t3, 15
add
$a0, $t1, $t2
sub
$a0, $a0, $t3
li
$v0, 1
syscall
li
$v0, 4
la
$a0, sep
syscall
(a) a0:= t1+4
(b) a0:= t1*8
(c) a0:= ((t1+t2)/4)+(t3 mod 2)
sep:
# a0:= t1+t2-t3
# a0=45
. data
sep : . asciiz " , "
. text
li
li
li
$t1 , 10
$t2 , 50
$t3 , 15
add
sub
jal
$a0 , $t1 , $t2
$a0 , $a0 , $t3
print
# a0 := t1 + t2 - t3
addi
jal
$a0 , $t1 , 4
print
# a0 := t1 +4
li
mul
jal
$t4 , 8
$a0 , $t1 , $t4
print
4
# a0 := t1 *8
exit :
print :
sll
jal
$a0 , $t1 , 3
print
# a0 := t1 *8
add
srl
li
div
mfhi
add
jal
j exit
$a0 , $t1 , $t2
$a0 , $a0 , 2
$t4 , 2
$t3 , $t4
$t4
$a0 , $a0 , $t4
print
# a0 := (( t1 + t2 )/4)+( t3 mod 2)
li
$v0 , 10
syscall
li
$v0 , 1
syscall
li
$v0 , 4
la
$a0 , sep
syscall
jr $ra
Remarque : l'instruction sll $a0, $t1, 3 peut être utilisé pour éviter d'utiliser le registre
$t4.
(d) Comment éviter de répéter systématiquement le code d'achage ?
En utilisant jal print où print est une étiquette contenant le code a répéter :
print:
li
syscall
li
la
syscall
jr $ra
$v0, 1
$v0, 4
$a0, sep
Question 3
Écrire le code ci-dessous en MIPS et exécuter le programme avec des valeurs e.g., i=2, j=2, g=7,
h=3
if (i=j) then
f := g+h;
else
f := g-h;
endif
print f
i:
main :
. data
. word 2 ,2 ,7 ,3
. text
la
lw
lw
lw
lw
bne
$a1 , i
$t0 ,0( $a1 )
$t1 ,4( $a1 )
$t2 ,8( $a1 )
$t3 ,12( $a1 )
$t0 , $t1 , else
# $t0 ! i
# $t1 ! j
# $t2 ! g
# $t3 ! h
# if ( i = j ) then
5
else :
endif :
add
$t4 , $t2 , $t3
j endif
sub
$t4 , $t2 , $t3
li
$v0 ,1
move
$a0 , $t4
syscall
# $f = g + h
# else
# $f = g - h
# endif
# print
Question 4
Considérer les tableaux T1 et T2 de taille 10 respectivement initialisés à {1,2,3,4,5,6,7,8,9,10} et
{10,10,10,10,10,10,10,10,10,10}.
(a) Coder en MIPS la boucle suivante et exécuter la sur les tableaux T1 et T2.
c:=10
for i in 1..10 loop
T2[i] := T1[i] + c;
end loop;
T1 :
T2 :
main :
loop :
end :
. data
. word 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10
. word 10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10 ,10
. text
la
la
li
li
li
$a1 , T1
$a2 , T2
$t1 ,0
$t2 ,9
$t3 ,10
# a1
# a2
# t1
# t2
# t3
=
=
=
=
=
adresse de T1
adresse de T2
i = 0
nombre d’itérations = 9
c = 10
bgt
lw
add
sw
addi
addi
addi
j
$t1 , $t2 , end
$t4 ,0( $a1 )
$t4 , $t4 , $t3
$t4 ,0( $a2 )
$t1 , $t1 ,1
$a1 , $a1 ,4
$a2 , $a2 ,4
loop
# for i in 1..10 loop
# t4 = T1 [ i ]
# t4 = T1 [ i ]+ c
# T2 [ i ]= T1 [ i ]+ c
# i = i +1
(b) Combien y-a-t-il d'instructions exécutées pendant l'exécution de ce code ? Combien de références
(lw, sw) à des données en mémoire seront faites pendant l'exécution ?
Nombre d'instructions exécutées : 7 avant le début de la boucle, 9 dans la boucle exécutée 10
fois. ⇒ 97.
Nombre de références : 1 lecture (lw) de la valeur de T1[i] et une écriture (sw) de la nouvelle
valeur de T2[i] par itération. ⇒ 20.
Voir chier td4-q4-count.s
Question 5
Écrire un programme MIPS qui calcule le carré d'un nombre saisi au clavier à l'aide d'un procédure
square dénie à une étiquette donné.
. data
square_out_string :
. asciiz
" \ nSquare : "
6
main :
exit :
. text
j test_square
li
$v0 , 10
syscall
# code for exit = 10
# call operating system
test_square :
li $v0 , 5
syscall
move $t0 , $v0
li $v0 , 4
la $a0 , square_out_string
syscall
move $a0 , $t0
jal square
move $a0 , $v0
li $v0 , 1
syscall
j exit
square : mul $v0 , $a0 , $a0
jr $ra
# code for reading integer
# save input int
# code for printing string
# load address of string
# pass input int as argument
# save the result
# code for printing integer
# compute the multiplication
Question 6
Écrivez un programme MIPS inversant l'ordre des octets d'un mot de 4 octets O1 O2 O3 O4 (e.g.,
0A0B0C0D) chargé au début du programme dans le registre $a0. A la n du programme, le registre
$v0 doit contenir le mot O4 O3 O2 O1 où les octets sont inversés (e.g., 0D0C0B0A).
str :
main :
inv :
. data
. asciiz
. text
li
lui
or
move
jal
move
j
addi
sw
li
jal
sll
li
jal
sll
or
li
jal
srl
or
li
jal
srl
or
lw
addi
" Octet inversé : "
$a0 ,0 x0C0D
$t0 ,0 x0A0B
$a0 , $a0 , $t0
$v0 , $0
inv
$t0 , $v0
print
$sp , $sp , -4
$ra ,0( $sp )
$a1 ,0
byte
$v1 , $v0 ,24
$a1 ,8
byte
$t0 , $v0 ,8
$v1 , $v1 , $t0
$a1 ,16
byte
$t0 , $v0 ,8
$v1 , $v1 , $t0
$a1 ,24
byte
$v0 , $v0 ,24
$v0 , $v0 , $v1
$ra ,0( $sp )
$sp , $sp ,4
#
#
#
#
load last 2 bytes in a0
load first 2 bytes in t0
load first 2 bytes in a0
initialize v0
# save result before printing
#
#
#
#
#
reserve space in stack
save ra in stack
shit amount argument for proc byte
v0 =000( o4 )
v1 =( o4 )000
# v0 =000( o3 )
# v1 =( o4 )( o3 )00
# v1 =( o4 )( o3 )( o2 )0
# v0 =000( o1 )
# v0 =( o4 )( o3 )( o2 )( o1 )
# restore ra
# restore sp
7
byte :
print :
jr
li
sllv
and
jr
$ra
$t0 ,0 xff
$t0 , $t0 , $a1
$v0 , $t0 , $a0
$ra
li
la
syscall
li
move
syscall
$v0 , 4
$a0 , str
# used to copy the appropriate byte
# shift left t0
# copy a0 in v0
$v0 , 1
$a0 , $t0
Question 7
Écrire la fonction factorielle et le code suivant en MIPS.
main () {
printf ("The factorial of 10 is ", fact (10));
}
int fact (int n) {
if (n < 1)
return (1);
else
return (n * fact (n - 1));
}
# Factorial
. data
out_str : . ascii " The factorial of 10 is "
main :
fact :
. text
subu
sw
sw
addiu
li
jal
move
li
la
syscall
li
move
syscall
lw
lw
addiu
li
syscall
subu
sw
sw
addiu
sw
lw
bgtz
$sp , $sp ,32
$ra ,20( $sp )
$fp ,16( $sp )
$fp , $sp ,28
$a0 ,10
fact
$t0 , $v0
$v0 , 4
$a0 , out_str
#
#
#
#
#
#
#
#
#
Reserve frame size
Save return address
Save old frame pointer
Set up frame pointer
Put argument (10) in $a0
Call factorial function
Move fact result
code for printing string
Put format string in $a0
$v0 , 1
$a0 , $t0
$ra ,20( $sp )
$fp ,16( $sp )
$sp , $sp ,32
$v0 , 10
# Restore return address
# Restore frame pointer
# Pop stack frame
$sp , $sp ,32
$ra ,20( $sp )
$fp ,16( $sp )
$fp , $sp ,28
$a0 ,0( $fp )
$v0 ,0( $fp )
$v0 , L2
#
#
#
#
#
#
#
8
Reserve frame size
Save return address
Save frame pointer
Set up frame pointer
Save argument ( n )
Load n
Branch if n > 0
L2 :
L1 :
li
j
$v0 ,1
L1
# Return 1
# Jump to code to return
lw
subu
move
jal
lw
mul
$v1 ,0( $fp )
$v0 , $v1 ,1
$a0 , $v0
fact
$v1 ,0( $fp )
$v0 , $v0 , $v1
lw
lw
addiu
jr
$ra , 20( $sp )
$fp , 16( $sp )
$sp , $sp , 32
$ra
#
#
#
#
#
#
#
#
#
#
#
9
Load n
Compute n - 1
Move value to $a0
Call factorial
Load n
Compute fact (n -1) * n
Result is in $v0
Restore $ra
Restore $fp
Pop stack
Return to caller
Téléchargement